On Oct 14, 2009, at 5:04 PM, Jim Blandy wrote:
One could characterize the difference by saying that Mozilla has
"reluctant properties" whereas WebKit has "reluctant values". :)
In other words, in WebKit, 'document.all' has a value --- a value
that can be assigned to other variables, stored in data structures,
and so on without changing its behavior --- but which is hard to get
a grip on.
I'm not sure "reluctant value" is a good way to summarize the
behavior. The term we use is "object that masquerades as undefined".
The value returned by document.all has a small set of behaviors that
are exhibited by the undefined value, but are not allowed by the spec
to values of object type.
Whereas, in Mozilla, 'document' sort-of-has and sort-of-doesn't-have
a property named 'all', depending on how you look at it.
It could just be organizational bias, but reluctant properties
strike me as the more bounded form of insanity.
Before you conclude that, let's consider the impact of host object
properties that return different values based on their syntactic
context. From the informal operational semantics given form ECMAScript
syntactic constructs, one might conclude that certain source-to-source
program transforms are sound, in the sense that they cannot possibly
alter the behavior of the program. Consider these two functions. I
will use %EXPR% as a metasyntactic variable, indicating any valid
JavaScript expression that can appear as the right-hand side of an
assignment:
function testFunc() {
var tmp;
func nested(e) { tmp = e; }
nested(%EXPR%);
return tmp;
}
function testFunc() {
var tmp = %EXPR%;
return tmp;
}
You might think this is a valid transformation no matter what %EXPR%
is, even if it involves hot objects. But this transformation is
unsound in Mozilla, for example if %EXPR% is document.all. In that
case, the first function will return the all collection and the second
will return undefined. Now, you might think this is kind of obscure,
and not a practically important transform. Sure, source-to-source
transformations could in theory factor out unneeded closures, but
would they really. However, consider this pair of functions:
function testFunc() {
var tmp = %EXPR%;
return tmp;
}
function testFunc() {
return %EXPR%;
}
You might think these are surely equivalent in all respects.
Converting in either direction seems like a really basic transform,
something that many ECMAScript program rewriters are likely to do. But
again, converting in either direction would be unsound for Mozlla, if
%EXPR% is document.all. The first function would return undefined, the
second all collection.
Going beyond what Mozilla does, let's say host object property or
method access can vary in arbitrary ways based on syntactic context.
Then *no* source-to-source transform is sound, not even changing
whitespace or stripping comments, unless you know the behavior of all
host objects the code will deal with.
It's true that an object which ToBoolean() converts as false violates
some assumptions, as does an object that compares == to undefined or
null. There are some otherwise valid identities for a value known to
be an object that this would break (though that knowledge would have
to come in some way other than 'typeof'). But I would claim this is a
more bounded form of insanity than the idea of expressions that have
different values depending on their surrounding source context. The
former requires just a limited number of additional permitted host
object exceptions. Tools that understand JavaScript object semantics
would just need a finite set of changes to consider the possibility of
objects that masquerade as undefined. The latter, if truly allowed by
the spec, makes source-to-source transformers, even something as
simple as a pretty-printer, potentially unsound. That seems like a
much less bounded form of insanity.
(It's been raised that debugging APIs may have behavior that depends
on the calling context. That may be true, but exposing debugging APIs
directly to normal code would violate important assumptions. For
example, the spec was tweaked to prevent exposing strict callers to
their non-strict callees, but it's commonplace for debugging APIs to
expose the full call stack. So I don't think the existence of
debugging APIs is a good argument that calling-context-sensitive host
objects are permissible in general. Also, looking at calling context
for the sake of performance optimizations does not create these kinds
of problems if observable behavior remains the same, so it's not a
helpful analogy.)
In any case, both the Mozilla and WebKit solutions for undetectable
document.all were pragmatic approaches to a problem with no perfect
solutions. Each has its downsides. I just wanted to explain some of
the less obvious consequences of Mozilla's approach, and of this kind
of mechanism in general.
Regards,
Maciej
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss