instanceof Operator

# Eugen.Konkov at aldec.com (18 years ago)

var a; a= {}; a instanceof Object //true a= []; a instanceof Array //true a='asdf'; a instanceof String //false a= 7; a instanceof Number //false

Why?

# liorean (18 years ago)

On 21/10/2007, Eugen.Konkov at aldec.com <Eugen.Konkov at aldec.com> wrote:

var a; a= {}; a instanceof Object //true a= []; a instanceof Array //true a='asdf'; a instanceof String //false a= 7; a instanceof Number //false

Why?

Because those are primitives of type double and string respectively. They are not instances of any of the compound types Object, String or Number.

Something silly that JavaScript inherited from Java that the world would be much better off without, but as I understand it won't be corrected because of real world compatibility problems.

# Eugen.Konkov at aldec.com (18 years ago)

Does instanceof operator check 'constructor' property in [proto] chain?

----- Original Message ---

# liorean (18 years ago)

On 21/10/2007, Eugen.Konkov at aldec.com <Eugen.Konkov at aldec.com> wrote:

Does instanceof operator check 'constructor' property in [proto] chain?

No. It uses the [[HasInstance]] private method of the object passed in as the right operand.

In the case of

'string' instanceof String;

F is String and 'string' is V in the following algorithm:

15.3.5.3 [[HasInstance]] (V)
Assume F is a Function object.
When the [[HasInstance]] method of F is called with value V, the
following steps are taken:
1. If V is not an object, return false.
2. Call the [[Get]] method of F with property name "prototype".
3. Let O be Result(2).
4. If O is not an object, throw a TypeError exception.
5. Let V be the value of the [[Prototype]] property of V.
6. If V is null, return false.
7. If O and V refer to the same object or if they refer to objects
joined to each other (section 13.1.2), return true.
8. Go to step 5.
# Jeff Dyer (18 years ago)

On 10/21/07 10:03 AM, liorean wrote:

On 21/10/2007, Eugen.Konkov at aldec.com <Eugen.Konkov at aldec.com> wrote:

var a; a= {}; a instanceof Object //true a= []; a instanceof Array //true a='asdf'; a instanceof String //false a= 7; a instanceof Number //false

Why?

Because those are primitives of type double and string respectively. They are not instances of any of the compound types Object, String or Number.

Something silly that JavaScript inherited from Java that the world would be much better off without, but as I understand it won't be corrected because of real world compatibility problems.

This problem is fixed by the addition of the 'is' operator in ES4. Replace 'instanceof' with 'is' in all of the above, and the result will be true in each case. You correctly point out that 'instanceof' is terminally broken for compatibility's sake.

# Lars T Hansen (18 years ago)

On 10/21/07, Jeff Dyer <jodyer at adobe.com> wrote:

On 10/21/07 10:03 AM, liorean wrote:

On 21/10/2007, Eugen.Konkov at aldec.com <Eugen.Konkov at aldec.com> wrote:

var a; a= {}; a instanceof Object //true a= []; a instanceof Array //true a='asdf'; a instanceof String //false a= 7; a instanceof Number //false

Why?

Because those are primitives of type double and string respectively. They are not instances of any of the compound types Object, String or Number.

Something silly that JavaScript inherited from Java that the world would be much better off without, but as I understand it won't be corrected because of real world compatibility problems.

This problem is fixed by the addition of the 'is' operator in ES4. Replace 'instanceof' with 'is' in all of the above, and the result will be true in each case. You correctly point out that 'instanceof' is terminally broken for compatibility's sake.

I don't think "is" fixes it, because "string" is not a subclass of "String" (for compatibility reasons) and "abcd" is "string". However,

"abcd" is string => true "abcd" instanceof string => true

The wrapper classes String, Number, Boolean are similar to the (primitive) values they wrap, but they're not really related to those value types in a type sense, and in ES4 the wrappers are of even less utility than in ES3, I would say.

# Jeff Dyer (18 years ago)

On 10/21/07 11:34 AM, Lars T Hansen wrote:

On 10/21/07, Jeff Dyer <jodyer at adobe.com> wrote:

On 10/21/07 10:03 AM, liorean wrote:

On 21/10/2007, Eugen.Konkov at aldec.com <Eugen.Konkov at aldec.com> wrote:

var a; a= {}; a instanceof Object //true a= []; a instanceof Array //true a='asdf'; a instanceof String //false a= 7; a instanceof Number //false

Why?

Because those are primitives of type double and string respectively. They are not instances of any of the compound types Object, String or Number.

Something silly that JavaScript inherited from Java that the world would be much better off without, but as I understand it won't be corrected because of real world compatibility problems.

This problem is fixed by the addition of the 'is' operator in ES4. Replace 'instanceof' with 'is' in all of the above, and the result will be true in each case. You correctly point out that 'instanceof' is terminally broken for compatibility's sake.

I don't think "is" fixes it, because "string" is not a subclass of "String" (for compatibility reasons) and "abcd" is "string". However,

"abcd" is string => true "abcd" instanceof string => true

The wrapper classes String, Number, Boolean are similar to the (primitive) values they wrap, but they're not really related to those value types in a type sense, and in ES4 the wrappers are of even less utility than in ES3, I would say.

Right, thanks for the correction. This is an obvious consequence of the recent return of primitive wrappers to ES4. 'string' is the new 'String'!

# Brendan Eich (18 years ago)

On Oct 21, 2007, at 11:48 AM, Jeff Dyer wrote:

The wrapper classes String, Number, Boolean are similar to the (primitive) values they wrap, but they're not really related to those value types in a type sense, and in ES4 the wrappers are of even less utility than in ES3, I would say.

Right, thanks for the correction. This is an obvious consequence of
the recent return of primitive wrappers to ES4. 'string' is the new
'String'!

String has its uses, not just embedded in content that requires
compatibility: string and String inter-convert, String is non-final,
and the two share a prototype object.

The need for string comes directly from ES1-3, because the primitive
string type in JS1 was auto-wrapped when you used a string value as
if it were an object, say to call a method on it. But since a new
wrapper was created each time (or so it appeared; implementations
could optimize), the object-ness of the primitive string was
ephemeral: you couldn't set methods and get them later; any get on
the wrapper for a property not found on String.prototype or above
would return undefined.

In ES4, string has catchalls to satisfy this ephemeral wrapper get/ set compatibility, but method calls on string instances do not
require String wrapper creation.

Wrapper creation may or may not be observable in ES3 -- 9.9 says
"create a new String" but does not say by evaluating |String| in
order to construct -- but ES4 does not allow any type name to be re- bound, so the implementations that chose to construct the wrapper by
reflecting on the current value of 'String' in the global object,
thereby allowing someone to replace that binding and spy on wrapper
construction, no longer need to reflect each time.

The shared prototype object allows for replacement of prototype
methods, which per ES1-3 and much compatibility-constraining content
on the web, remain mutably bound in the shared prototype object. Thus
in ES1-3, if you wrapped String.prototype.charAt with some AOP advice
function, your code calling "hi".charAt(0) will still run your advice.

Since ("hi instanceof String) was never true, it should not be true
in the new world. This is one reason string and String are peer
subtypes of Object, that is, string is not a subtype of String.

Tucker and others have hoped for a way to customize String, and since
it is non-final and convertible to string, the use-cases that want to
make custom objects that delegate to String.prototype should work
too. But it would be good to see some examples.

# P T Withington (18 years ago)

On 2007-10-21, at 14:48 EDT, Jeff Dyer wrote:

The wrapper classes String, Number, Boolean are similar to the (primitive) values they wrap, but they're not really related to those value types in a type sense, and in ES4 the wrappers are of even less utility than in ES3, I would say.

Right, thanks for the correction. This is an obvious consequence of
the recent return of primitive wrappers to ES4. 'string' is the new
'String'!

Yikes. I thought 'String' was being kept around so you could extend
it. Why is it that 'string' cannot be a sealed sub-type of (the open
class) 'String'?

# P T Withington (18 years ago)

On 2007-10-21, at 15:20 EDT, Brendan Eich wrote:

On Oct 21, 2007, at 11:48 AM, Jeff Dyer wrote:

The wrapper classes String, Number, Boolean are similar to the (primitive) values they wrap, but they're not really related to
those value types in a type sense, and in ES4 the wrappers are of even
less utility than in ES3, I would say.

Right, thanks for the correction. This is an obvious consequence of the recent return of primitive wrappers to ES4. 'string' is the new 'String'!

String has its uses, not just embedded in content that requires compatibility: string and String inter-convert, String is non-final, and the two share a prototype object.

I think Dylan would have made String an open subclass of the sealed
class string: www.opendylan.org/books/dpg/db_305.html

The need for string comes directly from ES1-3, because the primitive string type in JS1 was auto-wrapped when you used a string value as if it were an object, say to call a method on it. But since a new wrapper was created each time (or so it appeared; implementations could optimize), the object-ness of the primitive string was ephemeral: you couldn't set methods and get them later; any get on the wrapper for a property not found on String.prototype or above would return undefined.

In ES4, string has catchalls to satisfy this ephemeral wrapper get/ set compatibility, but method calls on string instances do not require String wrapper creation.

Are you saying for compatibility you have to maintain this 'ephemeral
wrapper' behavior?

Wrapper creation may or may not be observable in ES3 -- 9.9 says "create a new String" but does not say by evaluating |String| in order to construct -- but ES4 does not allow any type name to be re- bound, so the implementations that chose to construct the wrapper by reflecting on the current value of 'String' in the global object, thereby allowing someone to replace that binding and spy on wrapper construction, no longer need to reflect each time.

The shared prototype object allows for replacement of prototype methods, which per ES1-3 and much compatibility-constraining content on the web, remain mutably bound in the shared prototype object. Thus in ES1-3, if you wrapped String.prototype.charAt with some AOP advice function, your code calling "hi".charAt(0) will still run your advice.

Since ("hi instanceof String) was never true, it should not be true in the new world. This is one reason string and String are peer subtypes of Object, that is, string is not a subtype of String.

IWBNI there were a single test for string-ness. In ES3, you have to
say:

typeof x == 'string' || (typeof x == 'object && x instanceof String)

Am I right in thinking that in ES4 you will be able to say:

x is string

to ask the same question?

Tucker and others have hoped for a way to customize String, and since it is non-final and convertible to string, the use-cases that want to make custom objects that delegate to String.prototype should work too. But it would be good to see some examples.

My use case is for an annotated string, the result of a sprintf-like
formatter that remembers the objects associated with each
representation (so you can inspect a message for more detailed
information): svn.openlaszlo.org/openlaszlo/trunk/WEB-INF/lps lfc/debugger/LzMessage.lzs

# Lars T Hansen (18 years ago)

On 10/22/07, P T Withington <ptw at pobox.com> wrote:

IWBNI there were a single test for string-ness. In ES3, you have to say:

typeof x == 'string' || (typeof x == 'object && x instanceof String)

Am I right in thinking that in ES4 you will be able to say:

x is string

to ask the same question?

You ask

x is AnyString

instead. AnyString is a predefined union type containing String and string. (Ditto AnyBoolean, AnyNumber.)

# Brendan Eich (18 years ago)

On Oct 22, 2007, at 4:53 AM, P T Withington wrote:

String has its uses, not just embedded in content that requires compatibility: string and String inter-convert, String is non-final, and the two share a prototype object.

I think Dylan would have made String an open subclass of the sealed class string: www.opendylan.org/books/dpg/db_305.html

We can have dynamic subclasses of non-dynamic classes, but if String
<: string, then string can't be final, which precludes some
optimizations and (separate) simplifications. We think these matter
enough not to make String <: string.

Such a relation would also be "upside down" by comparison to ES1-3,
where the primitive string type is not an object type, and even if
you pretended it were, it would not be superior to, or more general
than, String (in any prototype-based or class-based sense). Exactly
the opposite is true: String is more general than string.

In ES4, string has catchalls to satisfy this ephemeral wrapper get/ set compatibility, but method calls on string instances do not require String wrapper creation.

Are you saying for compatibility you have to maintain this 'ephemeral wrapper' behavior?

Yes. The use-case is generic programming over string primitives and
bona-fide ES3 objects: you want to allow "hello" to flow into a
function farble(x) that gets and/or sets ad-hoc properties on x,
without exceptions being thrown. Such a function can't count on
getting what it set, of course (ephemeral wrappers). But it must fail
soft as it has for going on 12 years.

My use case is for an annotated string, the result of a sprintf-like formatter that remembers the objects associated with each representation (so you can inspect a message for more detailed information): svn.openlaszlo.org/openlaszlo/trunk/WEB-INF/lps lfc/debugger/LzMessage.lzs

Looks like it should derive from String and be happy in ES4. I'll
take a closer look later today.