The strange story of ! and ==(=)false

E

Evertjan.

Are ! and ==false equivalent? NO

<script type='text/javascript'>

alert('' == false); // true
alert(!''); // true

alert('000' == false); // true
alert(!'000'); // false

</script>

=================================

Could it be that ! and ===false are equvalent? NO

<script type='text/javascript'>

alert('' === false); // false
alert(!''); // true

alert('000' === false); // false
alert(!'000'); // false

</script>

=================================

So what the hell is the buggy logic of this?
 
V

VK

Are ! and ==false equivalent? NO

<script type='text/javascript'>

alert('' == false); // true
alert(!''); // true

alert('000' == false); // true
alert(!'000'); // false

</script>

=================================

Could it be that ! and ===false are equvalent? NO

<script type='text/javascript'>

alert('' === false); // false
alert(!''); // true

alert('000' === false); // false
alert(!'000'); // false

</script>

=================================

So what the hell is the buggy logic of this?

What exactly illogical do you see? http://www.jibbering.com/faq/notes/type-conversion/#tcBool
"Type conversion rules are even simpler for string to boolean
conversion as all non-empty strings always become true and empty
strings become false."

'000' === false means "are '000' and false of the same type and do
they contain the same value(s)?" What logic you want to apply to make
the answer yes (true)?
 
E

Evertjan.

Stefan Weiss wrote on 26 jun 2010 in comp.lang.javascript:
I don't think these rules are very logical or intuitive, but that's how
the language was specified. Personally, I don't even bother to remember
all of this. Don't use non-strict comparison with booleans and the
problem disappears.

I don't think that is enough for me, Stefan.

(x ==false) returns a boolean based on x after conversion to a boolean.

(! x) shoud do exactly the same.

I showed it does not in the case of x = '000',
so the Q is

is this ment to be so by definition?

or

is this simply a definition mistake?

Since both IE and Chrome have the same irregularity it would not be an
oimplementation mistake.

<FAQENTRY>
Should there be a warning for this strange phenomenon?
</FAQENTRY>
 
V

VK

I don't think that is enough for me, Stefan.

(x ==false) returns a boolean based on x after conversion to a boolean.

It is not what ('000' == false) exactly does: it first attempts to
treat '000' as a string representation of a number literal. '000' for
JavaScript is a valid literal of octal 0.
If the first step succeeded - and it did - then any non-zero value is
treated as true and 0 as false for logical comparison contexts.
Therefore the initial statement comes to (false == false) and it's
definitely true.

There are programming languages with an opposite approach, say in Perl
any string with length>=2 will be treated as true. What is more
logical depends on a particular taste.
(! x) should do exactly the same.

Not at all. It first creates new Boolean from '000', where if the
argument is omitted, or is false, 0, null, NaN, or an empty string,
the initial value is false; otherwise, the initial value is true.
Therefore the result for '000' is true. Then it applies NOT to the
current Boolean value, so the result is false.

I don't know (neither I do care) what "ECMAScript" does but JavaScript
does exactly that for the last 12 years at least (checked on NN 3.0
Gold out of my pure curiosity).
 
V

VK

If that was all there was to it, then "004" == "4" would also need tobe
true.

From what sky blue? String comparison goes by absolutely different
rules. Would you also claim that
("2+2" == "4") // should be true as well? :))

If still any doubts then try say
('0x0' == false) // true

This explanation is not correct. According to you, "002" == true should
return true. Let's try it out:

  "001" == true;     // true
  "002" == true;     // false

('0x0' == false) // true
('0x1' == false) // false
('0x2' == false) // false

The non-commutative logic, Sir. :) Forget about true, work with false
only.
Not at all. It first creates new Boolean from '000', [...]

No, it doesn't. There are no Boolean objects involved in this operation.

Again, we are not talking about some mysterious "ECMAScript" but about
JavaScript this ng is about. In JavaScript this object is heavily
involved in they way as described.
 
V

VK

Allow me to repeat my earlier recommendation, sir. Don't use either.

The "right" vs. "wrong" comparison approach summary I expressed to
Dimitry
http://groups.google.com/group/comp.lang.javascript/msg/7b28e70774742d92
The right one is the one that is right to you in this particular
situation, namely what do *you* want to treat as true or false. Let's
us not be mixing the boolean logic with the aesthetics and rights and
wrongs, good and bad respectively :) There can be situations when any
potential 0 must be false, so you want "0", "0x0" etc. to be false as
well. There can be situations where only non-emptiness of string
matters. There can be situations when you want false to be true and
vice versa (inverse logic). Without knowing that particular project
and its purpose no generalized pattern should/can be given.
(! x) should do exactly the same.
Not at all. It first creates new Boolean from '000', [...]
No, it doesn't. There are no Boolean objects involved in this operation.
Again, we are not talking about some mysterious "ECMAScript" but about
JavaScript this ng is about. In JavaScript this object is heavily
involved in they way as described.

Since we're talking about a hypothetical intermediate object, I'll
believe that when you can show me the source. The "mysterious
ECMAScript" specification doesn't describe the creation of such an
object, and I seriously doubt that there are any implementations out
there which would create one, just for fun. I could be mistaken, but
since it's your claim, the burden of proof is on you.

I am saying something and it correlates with the experimental results
down to NN 2.02 You are saying something and it doesn't explain the
experimental results down to NN 2.02 Who's the burden of proof is?
Upcasting and downcasting in JavaScript never were throughoutly
documented anywhere, it is a historical inheritance thing in the most
of its parts. A good sample is the implicit upcasting/downcasting of
string primitives like
var s = 'abc';
var l = s.length // here
and the "helper" for number primitives like
var n = 2;
window.alert( (n).toString(2) ); // here - no parenthesis for n =
error

One need to go to Netscape developers archives via wayback machine,
somewhere there I presume. Don't want to spend the week-end on that
really. Yet I didn't say "no".
 
V

VK

Upcasting and downcasting in JavaScript never were throughoutly
documented anywhere, it is a historical inheritance thing in the most
of its parts. A good sample is the implicit upcasting/downcasting of
string primitives like
 var s = 'abc';
 var l = s.length // here
and the "helper" for number primitives like
 var n = 2;
 window.alert( (n).toString(2) ); // here - no parenthesis for n =
error

One need to go to Netscape developers archives via wayback machine,
somewhere there I presume. Don't want to spend the week-end on that
really. Yet I didn't say "no".

OK, at the first glance the situation is rather funny: for 14 years
the original Netscape note for NN 2.0b pre-release was reproduced by
anyone:

<g>
All unary operators, such as the ! operator, evaluate expressions as
follows:
* If applied to undefined or null expressions, a run-time error is
raised.
* Objects are converted to strings.
* Strings are converted to numbers if possible. If not, a run-time
error is raised.
* Boolean values are treated as numbers (0 if false, 1 if true).
</g>

No one seem ever bothered to check that 95% of it is a complete bs. I
guess it was earlier thoughts for LiveScript, but it for the release
the potential amount of run-time errors was realized and all that
silliness replaced by introducing Boolean object and the implicit
upcasting/downcasting.

So the question is not to find some docs as they never were written
but to write for the first time ever upcasting/downcasting algorithm
for logical operations as it is.
 
V

VK

There's no error if you omit the parentheses around n. You may be
confusing that with something like (2).toString().

Right.
window.alert( "foo".length ); // 3
window.alert( 2.toString(2) ); // run-time error
window.alert( (2).toString(2) ); // 10
var n = 2; window.alert( n.toString(2) ); // 10
So different implicit up/down-casting for string literal, number
literal, number returning expression, identifier for number value. All
this still waits to be decently described for 14 years as well. Some
day maybe...
Anyway, that's not what I was talking about. In your example, there's a
reason why an object should be created: you want to access one of its
methods or properties. Even so, the object could potentially be
optimized away by a script engine, but at least the behavior is
described in terms of objects (yes, in the "mysterious" ECMAScript
specs), and the code looks as if there was an object. The same is not
true for the logical NOT operator. There's no mention of objects in the
specs, and the syntax doesn't suggest objects, either. You insist that
there's an Boolean object hidden in there somewhere, and that this
"correlates with the experimental results down to NN 2.02". How can you
experimentally test and confirm something which is never directly
accessible to you?
(unless you plan on building a Large Object Collider in Switzerland)

OK, I cannot "see" that temporary object wrapper just like I cannot
"see" that wrapper for "foo".length. Let's us say I do postulate its
existence - just like for the Higgs boson - as the only fully non-
contradictory explanation of the observed results. An LHC equivalent
could be to write yet another C++ program using say IActiveScript and
relevant interfaces. It is a ridiculous yet alas very common situation
to treat JavaScript implementation producers as some natural force of
the Universe unwillingly disclosing its secrets over time, efforts and
money consuming experiments... :) :-|
That appears to be a quote from Microsoft's JScript documentation, not a
Netscape document.

It is a Netscape stuff, I am 99% sure. MSDN documentation may be not a
perfect source. It may be a terrible source by some criteria. But I do
not recall a case where a written "you'll get this" would be 95% wrong
to the actual JScript results on a span of 5 paragraphs in the row. I
say it happened because "nobody will read it anyway, so copy'n'paste
quickly from the original source".
Not for me. What I'm saying is that in order to evaluate a logical NOT,
there's no need to create a Boolean object, get its value, and destroy
it immediately afterwards. You claim that this is exactly what happens
in JavaScript. The SpiderMonkey source is open; show me the code.
Oh, alright - if you can dig it up in the NN2 sources, I'll accept that
as proof, too. Deal?

I cannot give you the final deal because I am not sure if it was ever
documented anywhere. It could be just a call from Eric Lippert (M$) to
Brendan Eich (N^) some day back in 1996

" - man, how do you treat that?
- eh... let me see... crap... it gives me that.
- will it give this in the future?
- eh... crap... crap... ok, it will be so from now on,
but let not say it to anyone explicitly, ok?
- sure man, so I'm coding it this way. have a good one.
- you too man... thanks.
"

Such standardization mechanics was very common for the 1995-1998
period and respectively such proof can be lost forever. So far I put a
daemon to query the Wayback Machine, but 1996 archives are very slow,
so even if anything was ever printed - it may take some long time.
 
L

Lasse Reichstein Nielsen

VK said:
Right.
window.alert( "foo".length ); // 3
window.alert( 2.toString(2) ); // run-time error

Not runtime. Syntax error. The tokenization of this is
"window" "." "alert" "(" "2." "toString" "(" "2" ")" ")" ";"
The literal "2." (matched by the rule
DecimalLiteral ::
DecimalIntegerLiteral . DecimalDigits_opt ExponentPart_opt
) might not be what you intended, but it is what you wrote.

A number, "2.", followed by an identifier, "toString" doesn't match
any rule in the grammar, so you get a syntax error.
window.alert( (2).toString(2) ); // 10
var n = 2; window.alert( n.toString(2) ); // 10
So different implicit up/down-casting for string literal, number
literal, number returning expression, identifier for number value.

No, it's all handled during parsing. There is no more or less
"up/down-casting" whether you use a variable hondling a number or a
literal number.

See
alert(2..toString(2));
(which tokenizes as
"alert" "(" "2." "." "toString" "(" "2" ")" ")" ";"
)
All this still waits to be decently described for 14 years as
well. Some day maybe...

And it's all documented in the ECMAScript specification of the grammar,
well enough that all the implementors can figure it out.

/L
 
V

VK

I retract that. Do _not_ look at the SpiderMonkey parser/interpreter
code unless you're drunk or a wizard (or both).

Even that can be not enough for core stuff like that :) A drunk
smoking grass wizard would be comfortable I guess :) To be fair, it
is not Gecko only problem: any old enough system if ever studied
internally will kill anyone's programming illusions once and forever.
My personal hint: do *not* study Java core (anything below Swing) :)
I found an older version
lying around in my ~/build directory and got curious. Now I've got a
headache.

To make it short: after peeling away the onion-like layers of macros and
arcane typedefs that make up the JavaScript interpreter, and wrapping my
head around stuff like the difference between JS_ValueToBoolean and
js_ValueToBoolean, what it comes down to is this:

src/jsinterp.c
   ...
   BEGIN_CASE(JSOP_NOT)
      POP_BOOLEAN(cx, rval, cond);
      PUSH_OPND(BOOLEAN_TO_JSVAL(!cond));
   END_CASE(JSOP_NOT)
   ...
   #define POP_BOOLEAN(cx, v, b)
      ...
      ok = js_ValueToBoolean(cx, v, &b);   // [ed] branch for strings

src/jsbool.c
   ...
   js_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
   {
     ...
     } else if (JSVAL_IS_STRING(v)) {
         b = JSSTRING_LENGTH(JSVAL_TO_STRING(v)) ? JS_TRUE : JS_FALSE;
     ...
     }
     *bp = b;

The length of a string operand for JSOP_NOT (a.k.a. "!") is used to
decide whether the expression evaluates to true or false. There's no
creation of new Boolean objects anywhere. BOOLEAN_TO_JSVAL doesn't
create any, and JS_TRUE and JS_FALSE are (indirectly) defined as 1 and
0, respectively.

Shall we declare now that JavaScript doesn't have true and false
values as well? :) I can tell you right away that JavaScript doesn't
have any objects: on C level these are strings and number
manipulations as well and nothing else. And C itself does not have any
subroutines, identifiers and stuff: in the reality these are just
processor instructions and nothing else.

Talking about language - is not talking about the engine.

I am still collecting data at my spare time. I'll be back :)
 
V

VK

Talking about language - is not talking about the engine.

I am still collecting data at my spare time. I'll be back :)

That is already something:

The standard equality operators (== and !=) in JavaScript compare two
operands as numbers. If one of operands or both of them are not
numbers then before the comparison the conversion is made by following
rules:
....
JavaScript attempts to convert the string numeric literal to a Number
type value. First, a mathematical value is derived from the string
numeric literal. Next, this value is rounded to nearest Number type
value.
....
If one of the operands is Boolean, the Boolean operand is converted to
1 if it is true and +0 if it is false.
....
http://devedge-temp.mozilla.org/library/manuals/2000/javascript/1.3/reference/ops.html#1060974

So the case with ("000" == false) can be closed:

("000" == false) => (00 == false) => (0 == 0) => true

In general cases (stringValue == false) still need more details as
nowhere in *language* manuals I found the exact behavior for
stringValue cannot be converted into number of any base. I can be NaN
then because
("xxx" == false) // false
("xxx" == true) // false
Note: so my "non-commutative logic" has nothing to do with that, it
was my stupid explanation.

So for string value that cannot be converted into number of any base
the comparison result is always false for cases like
(stringPrimitiveValue == notStringPrimitiveValue)
Note: counterexamples?
 
V

VK

To be fair, it
is not Gecko only problem: any old enough system if ever studied
internally will kill anyone's programming illusions once and forever.

JägerMonkey ! That was that! Once I nearly broke my head trying to
recall the new engine name. That is what the Mozilla team trying to do
ASAP to keep on competition by the end of the year
http://hacks.mozilla.org/2010/03/improving-javascript-performance-with-jagermonkey/

But as I see it is not a new engine but an optimized SpiderMonkey
https://wiki.mozilla.org/JaegerMonkey
 
L

Lasse Reichstein Nielsen

....
In general cases (stringValue == false) still need more details as
nowhere in *language* manuals I found the exact behavior for
stringValue cannot be converted into number of any base. I can be NaN
then because
("xxx" == false) // false
("xxx" == true) // false

Correct, it converts to NaN.
Why try to guess it when the EMCAScript standard specifies exactly how
== works (in ES5, it's section 11.9.3):

In this case, the boolean is converted to a number (step 7) , and then
the string is converted to a number (step 5), with result NaN, and then
the rule for NaN says that the comparison yields false (step 1.c.i).
So for string value that cannot be converted into number of any base
the comparison result is always false for cases like
(stringPrimitiveValue == notStringPrimitiveValue)

Yes.
The possible notStringPrimtiveValues are boolean (handled above),
number (ditto), and null and undefined (no matching cases except 10).
Note: counterexamples?

Shouldn't be, by the specification.

/L
 
V

VK

...


Correct, it converts to NaN.
Why try to guess it when the EMCAScript standard specifies exactly how
== works (in ES5, it's section 11.9.3):

Because there is an engine specification and a language tutorial. They
are different.
11.9.3 The Abstract Equality Comparison Algorithm
tells maybe everything for any possible situation but it is not usable
for anyone besides some selected intellectuals. Are we suggesting to
learn JavaScript by ECMA-262 3rd ed? Please, tell me that you are just
kidding.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,077
Messages
2,570,566
Members
47,202
Latest member
misc.

Latest Threads

Top