Specifically, the expression
document.all ? true : false
results in false, but the expression
Boolean(document.all)
results in true. ECMA 9.2 specifies ToBoolean for Object converts to
true. Both the first operand of ? : (Section 11.12) and Boolean called
as a function (15.6.1) specify that ToBoolean should be used. What's
more, typeof document.all is "undefined", but "all" in document is
true.
From reading the SpiderMonkey source, I think that this conversion is
handled by js_ValueToBoolean:
http://lxr.mozilla.org/mozilla1.8.0/source/js/src/jsbool.c#184. This
function implements object -> true as ECMA specifies.
So how does this work? Can someone point me to a piece of host object
code in Firefox I could look at?
The relevant bug is https://bugzilla.mozilla.org/show_bug.cgi?id=412247.
Thanks,
Norris
> See what was done in
> https://bugzilla.mozilla.org/show_bug.cgi?id=248549
The main idea is to annotate in the generated bytecode the property
access with flags describing the nature of access. Then the native
code that is called to get/set properties can see that it was called
for in a boolean context, or in a method context or property access
context, see http://lxr.mozilla.org/seamonkey/source/js/src/jsobj.c#3159
.
Regards, Igor
Right, this is what required by ECMAScript specs. Javascript
implements both primitive boolean value and Boolean object wrapper. In
logical operations objects are being downcasted first to primitives
with Boolean(false) resulting in true in many circumstances. Try this
for instance in any browser:
<script>
var b1 = false;
var b2 = new Boolean(false);
/*1*/ window.alert(b1 ? 'true':'false'); // false
/*2*/ window.alert(b2 ? 'true':'false'); // true
</script>
The moral is that you never ever use Boolean wrapper for Javascript
except one very particular situation which is not presented here.
In your case document.all returns undefined which is in Boolean
constructor context equal to Boolean(false) which is situation /*2*/
in the sample above.
So the options are either to break Rhino compatibility with ECMAScript
or to use the right style of boolean operations. I actually highly
surprised that on
https://bugzilla.mozilla.org/show_bug.cgi?id=412247
people seem ready to rather patch Rhino like no big problem which is
sorry to say but IMO a total nonsense.
I believe that ECMA permits *host* objects to have any conversion
behaviour they wish, no?
Mike
No. It does allow them though to return platform-specific strings for
typeof operator. Say
typeof SomeActiveXObject == 'unknown'
for some ActiveX on IE and it is standard compliant. It is all
irrelevant to the current question any way, because
var foo = new Boolean(WhateverWhatsoever);
foo ? This() : That();
is fully under the ECMAScript regulation so has to act in the way it
is specified - and in the way it will actually act on any Javascript
enabled browser.
Personal coding preferences of a particular developer should not
override the specification IMO ;-)
Section 9.2. says ToBoolean converts any Object to true, and doesn't
distinguish between a host object and native object. Arguably, the
spec doesn't say whether host objects are Objects (with capital O), in
which case it'd actually not define boolean conversion of host objects
at all.
Finally, 8.6.2.6 defines [[DefaultValue]] for native objects and
_only_ for Number and String hints, suggesting it is not meant to be
used with any other hints anyway (and indeed isn't used with any other
hints in the spec).
All of these imply to me that host objects can not affect their
boolean evaluation according to the ES3 spec -- an if statement will
perform ToBoolean on its argument, and ToBoolean will return true for
any Object.
Attila.
On 2008.01.24., at 16:18, Mike Shaver wrote:
> On Jan 24, 2008 10:14 AM, VK <school...@yahoo.com> wrote:
>> On Jan 23, 1:48 am, Norris Boyd <norrisb...@gmail.com> wrote:
>>> Specifically, the expression
>>> document.all ? true : false
>>> results in false, but the expression
>>> Boolean(document.all)
>>> results in true.
>>
>> Right, this is what required by ECMAScript specs. Javascript
>> implements both primitive boolean value and Boolean object wrapper.
>> In
>> logical operations objects are being downcasted first to primitives
>> with Boolean(false) resulting in true in many circumstances.
>
> I believe that ECMA permits *host* objects to have any conversion
> behaviour they wish, no?
>
> Mike
And since ES3 permits host objects to return different values each
time a property is accessed, it is perfectly ok for a host object to
return undefined for document.all when it is accessed in the boolean
operation context and to return an object in the other cases.
Regards, Igor
In the OP's case the whole problem is solved per ECMAScript by
implicitly downcasting the Boolean object before using in ternary
operator:
var b1 = false;
var b2 = new Boolean(false);
alert(b1 ? 'true':'false'); // always OK
alert(b2 ? 'true':'false'); // Oops
alert((b2==true) ? 'true':'false'); // OK again
Really, should one type in (b2==true) as expected or to hack the
engine every time it doesn't behave as "me wanted"? I keep staying on
the first option :-)
Boolean(document.all) is true, AFAIK, and
alert(document.all ? "d.a" : "no d.a")
is governed by 11.12's steps 1 and 2 here. Our document host object
chooses to implement the getter for "all" in a way that depends on how
it's accessed, and I can't find any stricture in ECMA that would
require otherwise. (If there were one, dynamic properties like
document.all.foo would seem to be entirely impossible, since their
value depends on extra-script decisions and context as well.)
Once you _have_ a DocumentAll object by accessing document.all, I
don't believe its value conversion varies in any way counter to ECMA.
That you sometimes get a false value from the document.all getter is
entirely legal as far as I'm able to tell from my readings of ECMA.
Mike
But this is not about the boolean conversion. Try in Firefox
javascript:(document.all?1:0)
javascript:(Boolean(document.all)?1:0)
The first returns 0 since as the implementation in a boolean-checking
returns undefined for document.all. The second result gives 1 as here
document.all is in the argument-of-a-call context and the result is
the real object.
Regards, Igor
damn, I'm having typing disorder today...
"explicitly downcasting "
> On Jan 24, 2008 10:59 AM, Attila Szegedi <szeg...@gmail.com> wrote:
>> Section 8.6.2 says host objects can implement internal properties any
>> way they wish (including [[DefaultValue]](hint)) , however ToBoolean
>> type conversion as defined in section 9.2 doesn't use
>> [[DefaultValue]]
>> (Boolean).
>
> Boolean(document.all) is true, AFAIK, and
>
> alert(document.all ? "d.a" : "no d.a")
>
> is governed by 11.12's steps 1 and 2 here. Our document host object
> chooses to implement the getter for "all" in a way that depends on how
> it's accessed, and I can't find any stricture in ECMA that would
> require otherwise. (If there were one, dynamic properties like
> document.all.foo would seem to be entirely impossible, since their
> value depends on extra-script decisions and context as well.)
So document sometimes returns a boolean from [[Get]]("all"), and
sometimes returns an object. That's okay. But how can it decide what
to return? In other words, how does it detect "how it is accessed"?
(I'm really trying to understand this).
Attila.
It either returns undefined or an object.
> But how can it decide what
> to return? In other words, how does it detect "how it is accessed"?
In abstract terms the generated bytecode contains the necessary
information to describe the context of the call and that information
is passed to the native code responsible for the property access.
Implementation wise the property-access code in SpiderMonkey just
analyzes instructions in the bytecode that follows the property access
and adjusts the result accordingly.
Regards, Igor
You are still missing the point. Your document host object may return
anything you like as long as doesn't lead to feature spoofing, so
would be not interpreted as "feature is here" while feature is
missing. At this point I was wrong by saying that you have not such
right: you do - but lesser browser producers explore some freedom
rights so better for the community ;-) and this is such cases, so ol'
good undefined would be just perfect. Yet the table 9.2 gives you four
options for return value for a missing host property:
boolean true/false
Boolean(true/false)
undefined
null
0
""
Again: it is not the problem, the problem how an ECMAScript-compliant
engine has to handle any of such value if wrapped using Boolean
constructor. In the ternary operator an ECMAScript-compliant engine
has to resolve such Boolean object by default as true, no matter if it
is a wrapper over false or true.
var bool = new Boolean(false); // null, "", true, etc.
bool ? doTrue() : doFalse();
must branch onto doTrue, period.
If Boolean wrapper is really needed - I cannot think of a circumstance
but say if - then one needs explicit downcasting here to prevent false
positives. It is either
(bool == true) ? doTrue() : doFalse();
as already suggested or even more simple
!bool ? doTrue() : doFalse();
In any shall perform case the engine itself has to be patched in non-
ECMA way. For all complains of the kind one may suggest to read
ECMAScript 3rd ed. and/or forward to comp.lang.javascript for further
education :-)