"x.constructor == Foo" vs "x instanceof Foo"

J

John G Harris

IMO what's actually confusing about prototypes in javascript is that the
language tries to hide the prototypes behind constructor functions,
which when taken at face value (i.e. when you're making assumptions
based on the semantics of well known class-oriented systems) break at
the point where you start using "class" inheritance, and *then* you have
to re-think the way you're building objects. And then constructors
become more and more useless. At least, that's what happened to me.

I don't understand why you don't like constructors. In Java and similar
languages the compiler writes part of the constructor's code. The
compiler makes sure that the constructor creates and initialises the
instance's ancestor properties.

But this is javascript. You have to do this work yourself as the
compiler won't do it for you. You have to call the ancestor
constructors, in non-constructor mode, yourself. Or you can duplicate
the code that does the job. (There's usually more than one way to do
anything in javascript).

Likewise, in Java etc the compiler makes sure that the instance can
access its methods and its ancestor methods. It does this in any way it
wants. The programmer doesn't need to know, and probably can't know.

Again, this is javascript, where you have to do it yourself. One obvious
way is to build a prototype chain with a layer of methods attached to
each prototype object. Each object in the chain has to be constructed of
course. The obvious way to do this is to have a constructor for that
particular kind of prototype. (Why are people so frightened of doing
this?)

All this is very tedious and annoying to code. On the other hand, it's
much the same each time and can be done while thinking about the
difficult bits you haven't done yet.

The strange thing is that a prototype system like javascript has is in
principle much easier to comprehend (and implement) than systems where
classes are special.

Having to code it yourself with no help from the compiler means that you
end up with a much better idea of what's going on in the program. It
should also make it easier to understand what's happening in Java etc
where much is hidden from you. This is a Good Thing.

John
 
L

Lasse Reichstein Nielsen

Joost Diepenmaat said:
IMO what's actually confusing about prototypes in javascript is that the
language tries to hide the prototypes behind constructor functions,
which when taken at face value (i.e. when you're making assumptions
based on the semantics of well known class-oriented systems) break at
the point where you start using "class" inheritance, and *then* you have
to re-think the way you're building objects. And then constructors
become more and more useless. At least, that's what happened to me.

It happens to *lots* of people, probably most. Many never progress to
the point where the conflict between their internal model and the
actual model becomes too noticable to ignore.
The strange thing is that a prototype system like javascript has is in
principle much easier to comprehend (and implement) than systems where
classes are special.

Maybe, maybe not. In the "real world"(TM) we think in both concrete
objects (that bird over there) and concepts (bird - something with
beak and wings). This matches the class based modelling approach
well.

When you use prototypical inheritance, you will often keep a mental
distinction between the prototype objects and "real" instance objects
- they are different kinds of objects, but there is no language support
to enforce the distinction. It's a simple programming model, but not
necessarily a simpler mental model. The class/instance distinction
is part of the inherent complexity of the description, and it will
show up, whether your language supports it or not.

/L
 
L

Lasse Reichstein Nielsen

Thomas 'PointedEars' Lahn said:
Joost Diepenmaat wrote:
You should remove the entire footnote as it is pure nonsense.

FWIW, I would also suggest removing it, but only because I think it
confuzes more than it helps. What it says is technically correct, but
the word "class" is used in a different meaning than in the paragraph
that the footnote is for. I.e., it's not really relevant for that
paragraph. Or perhaps it could just be reduced to "The ECMAScript
standard only uses the word 'class' in a different meaning than it is
used in class based object orientation."

/L
 
J

Joost Diepenmaat

Lasse Reichstein Nielsen said:
Maybe, maybe not. In the "real world"(TM) we think in both concrete
objects (that bird over there) and concepts (bird - something with
beak and wings). This matches the class based modelling approach
well.

I'm not sure that it's useful for a programmer to think in concepts vs
concrete objects like that or that classes are really the right way to
model concepts. But I agree that they seem to make some kind of
intuitive sense. I still maintain that prototypes are actually simpler
to understand, though. I think that because prototypes need much less
"infrastructure" to make them work it turns out that in javascript at
least, you end up writing mechanisms yourself that you might take for
granted in, say, Java.
When you use prototypical inheritance, you will often keep a mental
distinction between the prototype objects and "real" instance objects
- they are different kinds of objects, but there is no language support
to enforce the distinction. It's a simple programming model, but not
necessarily a simpler mental model. The class/instance distinction
is part of the inherent complexity of the description, and it will
show up, whether your language supports it or not.

That's true. There are definitely lots of problems where you actually
want something /like/ a class-based system. But from my experience, the
main trouble with javascript prototypes (and solved by traditional class
systems) in those cases is that of initialisation of instance
properties. Most class based systems solve that problem by calling all
initializers of all (super-)classes for each instantiation
automatically. Javascript forces you do it explictly (but gives quite a
bit flexibility in return). I don't know what (if anything) other
prototype-based languages provide to make this issue easier to deal
with.
 
J

Joost Diepenmaat

John G Harris said:
I don't understand why you don't like constructors. In Java and similar
languages the compiler writes part of the constructor's code. The
compiler makes sure that the constructor creates and initialises the
instance's ancestor properties.

It's not that I don't like constructors, it's that I don't like that I
/have/ to use them, when I usually can't use them for actually
initializing the objects correctly, so I end up with a load of empty
constructors. They just seem like more or less useless fluff that could
have been avoided by just providing direct access to the prototype.

[ ... ]
Again, this is javascript, where you have to do it yourself. One obvious
way is to build a prototype chain with a layer of methods attached to
each prototype object. Each object in the chain has to be constructed of
course. The obvious way to do this is to have a constructor for that
particular kind of prototype. (Why are people so frightened of doing
this?)

Something is not quite as straightforward here as you make it seem. I'll
have to think about this and try some stuff.

[ ... ]
Having to code it yourself with no help from the compiler means that you
end up with a much better idea of what's going on in the program. It
should also make it easier to understand what's happening in Java etc
where much is hidden from you. This is a Good Thing.

100% agreed.
 
T

Thomas 'PointedEars' Lahn

Lasse said:
FWIW, I would also suggest removing it, but only because I think it
confuzes more than it helps.

It merely provides the author's misconceptions about the language.
What it says is technically correct,

No, it's not. There are no "system-defined classes" (in whatever meaning of
the word), and a conforming ECMAScript implementation has to provide the
built-in objects which names are merely designated by the value of their
internal [[Class]] property.
but the word "class" is used in a different meaning than in the paragraph
that the footnote is for. I.e., it's not really relevant for that
paragraph.

As I said, the paragraph as it now is, is pure nonsense.
Or perhaps it could just be reduced to "The ECMAScript standard only uses
the word 'class' in a different meaning than it is used in class based
object orientation."

Has anyone of you actually checked that? Well, I did.

The ECMAScript Language Specification (Edition 3 Final) uses the word
"class" only in the following contexts and in its corresponding meaning:

| 15.4 Array Objects
|
| Array objects give special treatment to a certain class of property names.
| [...]

| 15.4.4.11 Array.prototype.sort (comparefn)
|
| [...]
| NOTE The above conditions are necessary and sufficient to ensure that
| comparefn divides the set S into equivalence classes and that these
| equivalence classes are totally ordered.

| 15.10 RegExp (Regular Expression) Objects
|
| Atom ::
| PatternCharacter
| .
| \ AtomEscape
| CharacterClass
|
| CharacterClassEscape :: one of
| dDsSwW
|
| CharacterClass ::
| [ [lookahead ∉ {^}] ClassRanges ]
| [^ ClassRanges ]
|
| [aso.]

| 15.11 Error Objects
|
| Instances of Error objects are thrown as exceptions when runtime errors
| occur. The Error objects may also serve as base objects for user-defined
| exception classes.

| A Grammar Summary
|
| A.1 Lexical Grammar
| [...]
| FutureReservedWord :: one of See section 7.5.3
| abstract enum int short
| boolean export interface static
| byte extends long super
| char final native synchronized
| class float package throws
|
| [...]
| A.6 Universal Resource Identifier Character Classes
|
| [aso., see 15.10]

Everything else are all occurrences of "[[Class]]" which is clearly and
always referring to the internal [[Class]] property value (a string of
characters) that is purely (required as a) a specification mechanisms.
(The property name is merely unfortunate, to say the least.)

It is therefore simply ridiculous to conclude that there were
"system-defined classes" in ECMAScript or classes at all (as in "A user
cannot add a new class, though the host system may define more."). It is
even more ridiculous to say that these or the values for internal [[Class]]
property of the built-in objects "are not required to exist at all".

The Specification makes that one thing very clear:

| 4.2.1 Objects
|
| ECMAScript does not contain proper classes such as those in C++,
| Smalltalk, or Java, but rather, supports constructors which create objects
| by executing code that allocates storage for the objects and initialises
| all or part of them by assigning initial values to their properties.

One can only wonder what part of "does not contain [...] classes" he did not
get yet.


PointedEars
 
J

John G Harris

It's not that I don't like constructors, it's that I don't like that I
/have/ to use them, when I usually can't use them for actually
initializing the objects correctly, so I end up with a load of empty
constructors. They just seem like more or less useless fluff that could
have been avoided by just providing direct access to the prototype.
<snip>

I'm puzzled. The work of building your new object will obviously be
packaged in a function, either for tidiness or because you believe in
encapsulation. How do you describe this function : a user-constructor,
an outer-constructor? It has to be something like that. I'm puzzled
because I can't see which part of that work couldn't be put inside the
javascript constructor.

I'm also puzzled by your reference to 'the prototype'. Which meaning of
the word 'prototype' are you using?

Something is not quite as straightforward here as you make it seem. I'll
have to think about this and try some stuff.
<snip>

My web site has an example of what I'm thinking here :

<URL:http://www.jgharris.demon.co.uk/jsfeats/JSfeats.html#seca1p1>

It's very straightforward. It's also very tedious :-(


John
 
J

Joost Diepenmaat

John G Harris said:
I'm puzzled. The work of building your new object will obviously be
packaged in a function, either for tidiness or because you believe in
encapsulation. How do you describe this function : a user-constructor,
an outer-constructor? It has to be something like that. I'm puzzled
because I can't see which part of that work couldn't be put inside the
javascript constructor.

The objects will be created in a function, yes. But when you're using
prototypes to inherit behaviour, you often can't use the super-object's
constructors to initialize instance properties since that would set the
properties of the prototype instead. What you then end up with is an
empty constructor with a .prototype that takes care of the shared
properties (usually just the methods, possibly some default
values). Plus a function (or method) to set the properties of the
instance that can be called when you're instantiating the sub object.
I'm also puzzled by your reference to 'the prototype'. Which meaning of
the word 'prototype' are you using?

The internal [[prototype]].
<snip>

My web site has an example of what I'm thinking here :

<URL:http://www.jgharris.demon.co.uk/jsfeats/JSfeats.html#seca1p1>

It's very straightforward. It's also very tedious :-(

I see where my confusion was coming from. You're using twice as many
constructors as I do: one constructor to initialize the prototype and
another to initialize the instance, for each "type" of object. I
generally write the instance initializers as methods of the respecive
[[prototypes]] instead. I don't have anything lying around to show what
I mean right now...
 
T

Thomas 'PointedEars' Lahn

Joost said:
Thomas 'PointedEars' Lahn said:
Lasse said:
Joost Diepenmaat wrote:
Which should scare everybody enough while still being technically
correct :)
You should remove the entire footnote as it is pure nonsense.
FWIW, I would also suggest removing it, but only because I think it
confuzes more than it helps.
It merely provides the author's misconceptions about the language.
What it says is technically correct,
No, it's not. There are no "system-defined classes" (in whatever meaning of
the word), and a conforming ECMAScript implementation has to provide the
built-in objects which names are merely designated by the value of their
internal [[Class]] property.

As far as I can see the [[class]] property is there as a short-cut for
implementors to make comparisons and other operators behave more
efficiently. In other words, it's there as a "class-like" system for
types that may be implemented in all kinds of ways.

You have not said or written "class-like" at all.
Confusing and maybe misguided, but it ain't nonsense. Your tendency to
treat people who write things that you don't 100% agree with as idiots
tends to overshadow your usually correct technical assessments

You have stated that there were "system-defined classes" while referring to
the [[Class]] property. There are _not_. Admitting that error and your
misconception instead of blaming others of misunderstanding you, would help
a great deal to increase your credibility.
As far as implementations go, it's not at all unreasonable to assume
that there are such class-like things and the fact that they're
mentioned in the specs as such is - I assume - no acccident. They are
not /required/ to exist in any way, which is what the rest of the
paragraph is about.

You miss the point.
It is even more ridiculous to say that these or the values for
internal [[Class]] property of the built-in objects "are not required
to exist at all".

Of course that part is true. It's a direct consequence of the description
of internal properties.

It is only true because a conclusion ("system-defined classes a not required
to exist at all") drawn from a false supposition ("there are system-defined
classes") is always true.


PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
As far as I can see the [[class]] property is there as a short-cut for
implementors to make comparisons and other operators behave more
efficiently. In other words, it's there as a "class-like" system for
types that may be implemented in all kinds of ways.

You have not said or written "class-like" at all.

Ok, if *that's* what you're objecting to, fine. You're right.
 
T

Thomas 'PointedEars' Lahn

Joost said:
I updated the foot note.

http://joost.zeekat.nl/constructors-considered-mildly-confusing.html#1_

If anyone still objects to its content, please let me know why.

You state in the section "Objects and methods":

| For most intents, javascript does not have classes. 1]

As pointed out by several people here already, that is wrong. For
*all* intents, javascript (if we assume you use that term to refer
to implementations of the ECMAScript Specification up to Edition 3
by that, see below) does not have classes.

In the corresponding footnote you state:

| The specification mentions that every object should have an internal
| [[Class]] property. [...]

However, the ECMAScript Language Specification, Edition 3 Final, states in
its section 8.6.2:

| Every object (including host objects) must implement the [[Prototype]] and
| [[Class]] properties [...]
|
| The value of the [[Class]] property of a host object may be any value,
| even a value used by a built-in object for its [[Class]] property.
| The value of a [[Class]] property is used internally to distinguish
| different kinds of built-in objects. [...]

It is very important to recognize the key words "must", "should", and "may"
in a technical specification for what they are, and use them accordingly in
a technical discussion as they indicate the requirement level of a feature
(and so they are often emphasized with being written in all-uppercase).
"Must" indicates an absolute requirement for conformance, "should" indicates
a strong recommendation, and "may" indicates a conforming possibility that
is not necessarily a recommended one.


Your essay also lacks the necessary differentiation between the ECMAScript
Language Specification, one possible implementation of it,
Netscape/Mozilla.org JavaScript, and other implementations like Microsoft
JScript. On several occasions you mention a "Javascript" language and a
"javascript interpreter", however there are no such things. I would
consider the recognition of this difference to be a key point in
understanding the kind of programming that is discussed here.


HTH

PointedEars
 
J

Joost Diepenmaat

Thomas 'PointedEars' Lahn said:
You state in the section "Objects and methods":

| For most intents, javascript does not have classes. 1]

As pointed out by several people here already, that is wrong. For
*all* intents, javascript (if we assume you use that term to refer
to implementations of the ECMAScript Specification up to Edition 3
by that, see below) does not have classes.

You're right. I missed that point.
In the corresponding footnote you state:

| The specification mentions that every object should have an internal
| [[Class]] property. [...]
[...]

It is very important to recognize the key words "must", "should", and "may"
in a technical specification for what they are, and use them accordingly in
a technical discussion as they indicate the requirement level of a feature
(and so they are often emphasized with being written in all-uppercase).
"Must" indicates an absolute requirement for conformance, "should" indicates
a strong recommendation, and "may" indicates a conforming possibility that
is not necessarily a recommended one.

Fair point.
Your essay also lacks the necessary differentiation between the ECMAScript
Language Specification, one possible implementation of it,
Netscape/Mozilla.org JavaScript, and other implementations like Microsoft
JScript. On several occasions you mention a "Javascript" language and a
"javascript interpreter", however there are no such things. I would
consider the recognition of this difference to be a key point in
understanding the kind of programming that is discussed here.

In the the text, with "Javascript" and "Javascript interpreter" I meant
to refer to the various implementations of Ecma-262 3rd edition. I
should probably make that explicit.

That was useful. Thanks.
 
J

John G Harris

The objects will be created in a function, yes. But when you're using
prototypes to inherit behaviour, you often can't use the super-object's
constructors to initialize instance properties since that would set the
properties of the prototype instead. What you then end up with is an
empty constructor with a .prototype that takes care of the shared
properties (usually just the methods, possibly some default
values). Plus a function (or method) to set the properties of the
instance that can be called when you're instantiating the sub object.

In javascript there is usually more than one way of doing it, whatever
'it' might be. Even so, I think that here there is a danger of two
different jobs being tangled together in a way that causes problems.

One job is to build a prototype chain for use by all the objects of this
kind. This is done once, before any of the objects are created. (You
could give each object its own personal prototype chain, but why would
you?)

The other job is to give to each object of this kind its own personal
initial data values and a pointer to the shared prototype chain. This is
done many times, at each object creation.

These are separate jobs, done at different times. They shouldn't
overlap, even if they are packaged inside one data structure. If they
don't overlap then ancestor jobs don't overlap either, so no problems
with inheritance.


<snip>

My web site has an example of what I'm thinking here :

<URL:http://www.jgharris.demon.co.uk/jsfeats/JSfeats.html#seca1p1>

It's very straightforward. It's also very tedious :-(

I see where my confusion was coming from. You're using twice as many
constructors as I do: one constructor to initialize the prototype and
another to initialize the instance, for each "type" of object. I
generally write the instance initializers as methods of the respecive
[[prototypes]] instead. I don't have anything lying around to show what
I mean right now...

It's not really two constructors. Javascript has only one way to attach
an object to the front of a prototype chain in order to make the chain
longer : that's to use 'new' with a user-defined function. Call this an
extender function, then you'll remember that there are two kinds of
creation functions, one for each job (see above).


John
 
J

Joost Diepenmaat

[ ... ]
These are separate jobs, done at different times. They shouldn't
overlap, even if they are packaged inside one data structure. If they
don't overlap then ancestor jobs don't overlap either, so no problems
with inheritance.

Completely agreed.
It's not really two constructors. Javascript has only one way to
attach an object to the front of a prototype chain in order to make
the chain longer : that's to use 'new' with a user-defined
function. Call this an extender function, then you'll remember that
there are two kinds of creation functions, one for each job (see
above).

Right. For most of the code where I use a prototype chain containing
more than one or two custom prototypes I've found that having the
constructor abstracted away completely (only using automatically
generated empty constructors) made the code a lot simpler to write. In
the end though, I think it's mostly a question of taste.
 
J

John G Harris

Right. For most of the code where I use a prototype chain containing
more than one or two custom prototypes I've found that having the
constructor abstracted away completely (only using automatically
generated empty constructors) made the code a lot simpler to write. In
the end though, I think it's mostly a question of taste.

Yes. There are several ways of doing it.

Therefore, your web page should make it clear that your complaints about
javascript are aimed at your way of doing it. Other people have no need
to complain.

John
 
J

Joost Diepenmaat

John G Harris said:
Yes. There are several ways of doing it.

Therefore, your web page should make it clear that your complaints about
javascript are aimed at your way of doing it. Other people have no need
to complain.

Why would I do that?

On that page I'm pointing out some potentially confusing things that can
happen with constructors. *You* may not find them confusing, but at
least some people would - they confused me when I first ran into them
and they confused the person who originally started this thread - so I
tried to explain what's happening as clearly and objectively as I could.

I do have some complaints about the whole constructor-prototype idea in
general and I have sketched out some ways that I like to work around
them, but none of that is on that page, or even site. Most of it in this
thread, which people can read for themselves.
 
J

John G Harris

Why would I do that?

On that page I'm pointing out some potentially confusing things that can
happen with constructors. *You* may not find them confusing, but at
least some people would - they confused me when I first ran into them
and they confused the person who originally started this thread - so I
tried to explain what's happening as clearly and objectively as I could.

I do have some complaints about the whole constructor-prototype idea in
general and I have sketched out some ways that I like to work around
them, but none of that is on that page, or even site. Most of it in this
thread, which people can read for themselves.

I'll just remind you of how you introduced us to that web page :

<quote>
Just to give you some examples of what can go wrong with the IMO nasty
"new constructor()" syntax:
</quote>

John
 
J

Joost Diepenmaat

I'll just remind you of how you introduced us to that web page :

<quote>
Just to give you some examples of what can go wrong with the IMO nasty
"new constructor()" syntax:
</quote>

What part of IMO do you not understand?
 
J

Joost Diepenmaat

Just FYI: the introduction to that page was at msg-id
<[email protected]>, in this thread, about 8 hours earlier, you
may have missed it then:

"I had some free time this weekend to do a somewhat extensive write-up
about this problem. It may be of interested to some people.

http://joost.zeekat.nl/constructors-considered-mildly-confusing.html

Feel free to ask questions or comment if it seems wrong or
incomprehensible."

Note, the "this problem" refers to the OP of this thread.
 

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
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top