Type Checking?
On Oct 10, 2007, at 3:53 PM, Garrett Smith wrote:
Typechecking is a problem.
typeof is limited and allows host objects to return anything. The problem is that some host objects return "function", for example, a NodeList in Safari. This is perfectly legal, according to the spec.
See bugs.ecmascript.org/ticket/153 -- for a general, universal
is-it-callable test, you would write
if (it is Callable) ...
How is type checking addressed in ES4?
The |is| operator tests universal or Platonic type, which involves
shared, immutable type descriptors that do not vary across windows or
frames. So
if (a is Array) ...
will work no matter where a was constructed.
On 10/10/07, Brendan Eich <brendan at mozilla.org> wrote:
On Oct 10, 2007, at 3:53 PM, Garrett Smith wrote:
Typechecking is a problem.
typeof is limited and allows host objects to return anything. The problem is that some host objects return "function", for example, a NodeList in Safari. This is perfectly legal, according to the spec.
See bugs.ecmascript.org/ticket/153 -- for a general, universal is-it-callable test, you would write
if (it is Callable) ...
How is type checking addressed in ES4?
The |is| operator tests universal or Platonic type, which involves shared, immutable type descriptors that do not vary across windows or frames. So
if (a is Array) ...
will work no matter where a was constructed.
Immutable type descriptor. I like it!
On 10/10/07, Brendan Eich <brendan at mozilla.org> wrote:
On Oct 10, 2007, at 3:53 PM, Garrett Smith wrote:
if (it is Callable) ...
The |is| operator tests universal or Platonic type, which involves shared, immutable type descriptors that do not vary across windows or frames. So
if (a is Array) ...
will work no matter where a was constructed.
I wonder how host objects will deal with this.
Will there be a transitive relationship of callable and ()?
If an object accepts arguments, it is callable, and if it is callable, it supports ,call(), right?
typeof appendChild; // "object" appendChild is Callable; // ???
In IE, appendChild.call is undefined, yet accepts arguments. It's like a host function that's bound, internally, to its node. Its thisArg is always the node; execution context is irrelevant. It's an odd duck.
document.all(), document.links(0) are also non-functional, but "do something" when you use arguments (). That something is not [[call]]. Opera mimicked this odd behavior with document.all and Mozilla did too in BackCompat mode.
Hosts that create such objects create a deceptive and confusing interface. It's like "what the heck is this thing?"
Garrett
On 10/11/07, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
If an object accepts arguments, it is callable, and if it is callable, it supports ,call(), right?
Assuming you mean "has itself a Callable member named 'call'", then I think the answer is no -- being Callable means having a [[Call]] operation defined on it, but that operation need not be reflected as a method on the function. You'll be able to use function-call syntax on it, though, which is what typically invokes the [[Call]] operation.
Mike (long-time listener, first-time caller)
On Oct 11, 2007, at 1:36 PM, Garrett Smith wrote:
On 10/10/07, Brendan Eich <brendan at mozilla.org> wrote:
On Oct 10, 2007, at 3:53 PM, Garrett Smith wrote: if (it is Callable) ...
I wonder how host objects will deal with this.
Will there be a transitive relationship of callable and ()?
For transitivity you need a binary relation. The |is| operator is
binary and transitive. The () operator is not binary and not in any
general sense transitive. So I'm not sure what you mean here, but
moving on:
If an object accepts arguments, it is callable, and if it is callable, it supports ,call(), right?
You mean if (it is Callable) then it.call(thisp, arg1, ..., argN)
works? No, because (it is Callable) is true for cases where !(it
instanceof Function). If you want to apply or call a non-function
callable, use Function.apply(callable, thisp, argArray) or
Function.call(callable, thisp, arg1, ...argN).
typeof appendChild; // "object" appendChild is Callable; // ???
See the ticket I cited, bugs.ecmascript.org/ticket/153, where
the Callabe structural type is defined as { meta::invoke: * } (or
possibly { meta::invoke: Function }). That is, if any object
implements the meta-object hook for invocation, it is callable. As
shaver notes and ES1-3 put it, this is the [[Call]] meta-method. It
is exposed in ES4 as meta::invoke. If some future rev of IE (not
retrofitted with ScreamingMonkey :-/) has a callable DOM method
appendChild, but (appendChild is Callable) evaluates to false, well,
that would be a bug.
In IE, appendChild.call is undefined, yet accepts arguments. It's like a host function that's bound, internally, to its node. Its thisArg is always the node; execution context is irrelevant. It's an odd duck.
That's not something ES4 will prescribe, but again: use the new-in- ES4 static generic Function.call (or Function.apply) if you need to.
document.all(), document.links(0) are also non-functional, but "do something" when you use arguments (). That something is not [[call]]. Opera mimicked this odd behavior with document.all and Mozilla did too in BackCompat mode.
I don't know what "BackCompat mode" means, but we do reflect
document.all if a script uses it without object-detecting it, and
only in such cases (since many well-written scripts fork based on if
(document.all) ... else ... tests and we want to run the else clause).
This is all not normatively specified by ES4. It's fodder for a
future WHAT-WG or W3C webapi spec on ES4 DOM binding. But we are
providing the tools for generalizing callability apart from (it
instanceof Function), and we are providing static-generic Function.
{apply,call}. These should be enough.
Hosts that create such objects create a deceptive and confusing interface. It's like "what the heck is this thing?"
I agree, and Gecko's DOM takes pains to reflect methods as instances
of Function, as far as I know.
I believe this came up on a w3c list in the last year, possibly
webapi or html-wg. Can someone find the thread?
On 10/11/07, Brendan Eich <brendan at mozilla.org> wrote:
On Oct 11, 2007, at 1:36 PM, Garrett Smith wrote:
On 10/10/07, Brendan Eich <brendan at mozilla.org> wrote:
On Oct 10, 2007, at 3:53 PM, Garrett Smith wrote: if (it is Callable) ...
I wonder how host objects will deal with this.
Will there be a transitive relationship of callable and ()?
For transitivity you need a binary relation. The |is| operator is binary and transitive. The () operator is not binary and not in any general sense transitive. So I'm not sure what you mean here, but moving on:
If an object accepts arguments, it is callable, and if it is callable, it supports ,call(), right?
You mean if (it is Callable) then it.call(thisp, arg1, ..., argN) works? No, because (it is Callable) is true for cases where !(it instanceof Function). If you want to apply or call a non-function callable, use Function.apply(callable, thisp, argArray) or Function.call(callable, thisp, arg1, ...argN).
So these are equivalent?
aNonFunctionCallableObj() Function.call( aNonFunctionCallableObj )
typeof appendChild; // "object" appendChild is Callable; // ???
See the ticket I cited, bugs.ecmascript.org/ticket/153, where the Callabe structural type is defined as { meta::invoke: * } (or possibly { meta::invoke: Function }). That is, if any object implements the meta-object hook for invocation, it is callable. As shaver notes and ES1-3 put it, this is the [[Call]] meta-method. It is exposed in ES4 as meta::invoke. If some future rev of IE (not retrofitted with ScreamingMonkey :-/) has a callable DOM method appendChild, but (appendChild is Callable) evaluates to false, well, that would be a bug.
If an object is invokable with arguments (), but not a Callable, it's impossible to type check. IE's call-like operation on with () is not [[call]].
Microsoft often says that it is necessary to retain backwards compatibility. I would hope they would
Mozilla has this weird function-like thing, too, (only with document.all, which is not used much anymore)
In IE, appendChild.call is undefined, yet accepts arguments. It's like a host function that's bound, internally, to its node. Its thisArg is always the node; execution context is irrelevant. It's an odd duck.
That's not something ES4 will prescribe, but again: use the new-in- ES4 static generic Function.call (or Function.apply) if you need to.
document.all(), document.links(0) are also non-functional, but "do something" when you use arguments (). That something is not [[call]]. Opera mimicked this odd behavior with document.all and Mozilla did too in BackCompat mode.
I don't know what "BackCompat mode" means, but we do reflect document.all if a script uses it without object-detecting it, and only in such cases (since many well-written scripts fork based on if (document.all) ... else ... tests and we want to run the else clause).
document.compatMode "CSS1Compat" -- standards mode "BackCompat" - quirks mode
BackCompat supports document.all
This is all not normatively specified by ES4. It's fodder for a future WHAT-WG or W3C webapi spec on ES4 DOM binding. But we are providing the tools for generalizing callability apart from (it instanceof Function), and we are providing static-generic Function. {apply,call}. These should be enough.
Hosts that create such objects create a deceptive and confusing interface. It's like "what the heck is this thing?"
I agree, and Gecko's DOM takes pains to reflect methods as instances of Function, as far as I know.
Mozilla really made document.all look like IE's weird collection-that-can-be-invoked-with-().
document.all.call(document, 0)
- Non-standard document.all property was used. Use W3C standard document.getElementById() instead.
- [Break on this error] undefined javascript: with ... (line 1) document.all.call is not a function
Yikes!
I believe this came up on a w3c list in the last year, possibly webapi or html-wg. Can someone find the thread?
I'll look for that.
Garrett
Incomplete sentence
On Oct 11, 2007, at 8:02 PM, Garrett Smith wrote:
If you want to apply or call a non-function callable, use Function.apply(callable, thisp, argArray) or Function.call(callable, thisp, arg1, ...argN).
So these are equivalent?
aNonFunctionCallableObj() Function.call( aNonFunctionCallableObj )
We don't need to go back and forth -- I wrote essentially the same
thing, but included the optional arguments. The two expressions you
wrote are equivalent assuming the global object should bind to |this|
for both to be equivalent.
If an object is invokable with arguments (), but not a Callable, it's impossible to type check. IE's call-like operation on with () is not [[call]].
Why do you say that? There's no reflection of [[Call]] into the
language yet, so how can you tell?
(Don't rely on typeof x == "function" meaning x.[[Call]] exists --
browsers do not follow ES3 here, although we tried in SpiderMonkey
for years before throwing in the towel.)
Microsoft often says that it is necessary to retain backwards compatibility. I would hope they would
You're barking up the wrong tree here. This is es4-discuss.
Mozilla has this weird function-like thing, too, (only with document.all, which is not used much anymore)
As I keep saying, any reflection of document.all in an ES4 "DOM level
0 plus IE quirks" binding should indeed make (document.all is
Callable) => true.
I don't know what "BackCompat mode" means, but we do reflect document.all if a script uses it without object-detecting it, and only in such cases (since many well-written scripts fork based on if (document.all) ... else ... tests and we want to run the else
clause).document.compatMode "CSS1Compat" -- standards mode "BackCompat" - quirks mode
BackCompat supports document.all
No, you're mixing things up. As I wrote, our document.all emulation
has nothing to do with DOM specs or document.compatMode, and it works
irrespective of the latter's value.
Mozilla really made document.all look like IE's weird collection-that-can-be-invoked-with-().
Like, yeah -- that was the point!
On 10/11/07, Brendan Eich <brendan at mozilla.org> wrote:
On Oct 11, 2007, at 8:02 PM, Garrett Smith wrote:
If you want to apply or call a non-function callable, use Function.apply(callable, thisp, argArray) or Function.call(callable, thisp, arg1, ...argN).
So these are equivalent?
aNonFunctionCallableObj() Function.call( aNonFunctionCallableObj )
We don't need to go back and forth -- I wrote essentially the same thing, but included the optional arguments. The two expressions you wrote are equivalent assuming the global object should bind to |this| for both to be equivalent.
If an object is invokable with arguments (), but not a Callable, it's impossible to type check. IE's call-like operation on with () is not [[call]].
Why do you say that? There's no reflection of [[Call]] into the language yet, so how can you tell?
Well yeah, you're right, I don't know, it's just a lame guess.
Some evidence:
- The caller does not provide a reference to the object it acts on.
- The typeof operator. typeof appendChild == "object"; // true.
I don't know what it is.
(Don't rely on typeof x == "function" meaning x.[[Call]] exists -- browsers do not follow ES3 here, although we tried in SpiderMonkey for years before throwing in the towel.)
Microsoft often says that it is necessary to retain backwards compatibility. I would hope they would
You're barking up the wrong tree here. This is es4-discuss.
Ok. I meant to say "hope they would not continue with this" (or something like that). Host objects that can act like functions but not be functions are confusing.
So that that's out of scope for ES4; it's OK for host objects to have custom behavior.
Mozilla has this weird function-like thing, too, (only with document.all, which is not used much anymore)
As I keep saying, any reflection of document.all in an ES4 "DOM level 0 plus IE quirks" binding should indeed make (document.all is Callable) => true.
I don't know what "BackCompat mode" means, but we do reflect document.all if a script uses it without object-detecting it, and only in such cases (since many well-written scripts fork based on if (document.all) ... else ... tests and we want to run the else clause).
document.compatMode "CSS1Compat" -- standards mode "BackCompat" - quirks mode
BackCompat supports document.all
No, you're mixing things up. As I wrote, our document.all emulation has nothing to do with DOM specs or document.compatMode, and it works irrespective of the latter's value.
quirksmode -- document.all works strict mode -- no document.all
It is detectable.
"all" in document
Mozilla really made document.all look like IE's weird collection-that-can-be-invoked-with-().
Like, yeah -- that was the point!
Was heavily debated and implemented. Water under the bridge, right?
Garrett
On Oct 11, 2007, at 10:36 PM, Garrett Smith wrote:
So that that's out of scope for ES4; it's OK for host objects to have custom behavior.
I'm afraid so, but we could say that host objects that are callable
SHOULD be functions if they appear to be functions otherwise; we
could say that all callable host objects MUST be compatible with the
Callable structural type.
quirksmode -- document.all works strict mode -- no document.all
It is detectable.
Sorry, you are right -- I didn't grok the document.compatMode
reference, but yeah: based on DOCTYPE we either will resolve
undetected document.all, or not.
Mozilla really made document.all look like IE's weird collection-that-can-be-invoked-with-().
Like, yeah -- that was the point! Was heavily debated and implemented. Water under the bridge, right?
Way under. See
Typechecking is a problem.
typeof is limited and allows host objects to return anything. The problem is that some host objects return "function", for example, a NodeList in Safari. This is perfectly legal, according to the spec.
Checking instanceof between frames doesn't work.
var i = document.getElementsByTagName("iframe")[0].contentWindow;
i.someFunction instanceof Function; // false.
How is type checking addressed in ES4?
Garrett