inheritance issue, seems to be sharing data incorrectly

M

Marcin

Hi everyone,
What I'm trying to achieve with the below code is
1. create a base 'class', called List
2. derive a 'class' from it called AList
3. derive another 'class' from AList, called BList, and then create
instances of both AList and BList()

The problem I have is that at step 3, when I create instances, the two
instances seem to share the same data, incorrectly. The blist()
variable at the end hasn't had anything added to it, yet it contains
what was added to the alist().

Can anyone could explain to me what I'm doing wrong ( tried something
like this on an ASP server running JScript, and using Firefox and both
give me the same results, so I'm guessing I'm misunderstanding this).

Thanks in advance
-Marcin


function print(str) {
console.log(str + "<br>");
}
var List = function() {
this.items = [];
}
List.prototype.add = function( num ) {
this.items.push(num);
return this;
}
List.prototype.toString = function() {
return this.items.join(" -- ");
}

var AList = function() {
}
AList.prototype = new List();

var BList = function() {
}
BList.prototype = new AList();
var alist = new AList();
alist.add(2);
alist.add(4);
print("alist is " + alist); //a list should have 2 and 4 printed out
var blist = new BList();
print("blist is " + blist); //b list shouldn't have anything, but it
does.
 
R

Richard Cornford

Hi everyone,
What I'm trying to achieve with the below code is
1. create a base 'class', called List
2. derive a 'class' from it called AList
3. derive another 'class' from AList, called BList, and
then create instances of both AList and BList()

The problem I have is that at step 3, when I create
instances, the two instances seem to share the same data,
incorrectly.

The sharing is as programme, which is correctly if maybe not
intentionally.
The blist() variable at the end hasn't had anything added
to it, yet it contains what was added to the alist().

The things that were added were not added to the BList instance, but
rather to an array that is referred to by the - items - property of
the BList instance. The value of that - itmes - property (the value is
a reference to an object) has been inherited through the BList
instance's prototype chain.
Can anyone could explain to me what I'm doing wrong

If you want a single object instance to 'own' another (single instance
of an) object then you will have to create one instance of the second
object as you create the instance of the first. That could be in the
constructor for the first, or in a method called from the constructor.
( tried something like this on an ASP server running JScript,
and using Firefox and both give me the same results, so I'm
guessing I'm misunderstanding this).

Yes, the behaviour is as designed/specified/expected so it should not
vary between ECMAScript implementations.

function print(str) {
console.log(str + "<br>");}

var List = function() {
this.items = [];}
^^^^^^^^^^^^^^^
This is the only point in this code where an array object is created
and assigned to an - item - property.
List.prototype.add = function( num ) {
this.items.push(num);
return this;}

List.prototype.toString = function() {
return this.items.join(" -- ");

}

var AList = function() {}

AList.prototype = new List();
^^^^^^^^^^
This is the only point in this code where the code that creates an
array and assigned it to the - items - property is called/gets
executed. That code is only executed once, so only one array object
every gets created.
var BList = function() {}

BList.prototype = new AList();
var alist = new AList();
alist.add(2);
alist.add(4);
print("alist is " + alist); //a list should have 2 and 4 printed out
var blist = new BList();
print("blist is " + blist); //b list shouldn't have anything,
but it does.

There is only one array, so that array holds all the values push-ed
onto it by any object that inherits the - items - property and the -
add - method.

Richard.
 
T

Thomas 'PointedEars' Lahn

Marcin said:
What I'm trying to achieve with the below code is
1. create a base 'class', called List
2. derive a 'class' from it called AList
3. derive another 'class' from AList, called BList, and then create
instances of both AList and BList()

The problem I have is that at step 3, when I create instances, the two
instances seem to share the same data, incorrectly. The blist()
variable at the end hasn't had anything added to it, yet it contains
what was added to the alist().

Can anyone could explain to me what I'm doing wrong ( tried something
like this on an ASP server running JScript, and using Firefox and both
give me the same results, so I'm guessing I'm misunderstanding this).
[...]
AList.prototype = new List();

If you search the archives for '"prototype = new" OR inheritFrom OR clone'
you will find the answer several times.

<http://jibbering.com/faq/#posting>


PointedEars
 
D

David Mark

Hi everyone,
What I'm trying to achieve with the below code is
1. create a base 'class', called List

There are no classes in Javascript. There are prototypes.
2. derive a 'class' from it called AList
3. derive another 'class' from AList, called BList, and then create
instances of both AList and BList()

No instances either. There are constructed objects.
The problem I have is that at step 3, when I create instances, the two
instances seem to share the same data, incorrectly. The blist()
variable at the end hasn't had anything added to it, yet it contains
what was added to the alist().

Can anyone could explain to me what I'm doing wrong ( tried something
like this on an ASP server running JScript, and using Firefox and both
give me the same results, so I'm guessing I'm misunderstanding this).

You are misunderstanding how inheritance works in JS. Perhaps you are
used to the classical model?
Thanks in advance
-Marcin

function print(str) {
        console.log(str + "<br>");}

var List = function() {
        this.items = [];}

List.prototype.add = function( num ) {
        this.items.push(num);
        return this;}

List.prototype.toString = function() {
        return this.items.join(" -- ");

}

var AList = function() {}

There is your first mistake. You didn't call the - List -
constructor.
AList.prototype = new List();

Second mistake obscures the first as this newly constructed object has
an items property, but clearly you didn't intend for all - AList -
objects to share the same array.
var BList = function() {}

Same as above.
BList.prototype = new AList();

And again, there is no new array created. Now all - BList - objects
will share that one array.
var alist = new AList();
alist.add(2);
alist.add(4);
print("alist is " + alist); //a list should have 2 and 4 printed out
var blist = new BList();
print("blist is " + blist); //b list shouldn't have anything, but it
does.

It certainly should have something as its - items - property
references the same array.

The question that comes up here often is how to write such a thing
elegantly. Unfortunately, object construction is a bit clunky in JS.

Should look something like this:

var List = function() {
this.items = [];
};

List.prototype = {
add: [...],
toString: [...]
};

var AList = function() {
List.call(this);
};

AList.prototype = clone(List.prototype);

var BList = function() {
AList.call(this);
};

BList.prototype = clone(AList.prototype);

Search the archive for the clone (AKA inheritFrom) function and lots
of examples.
 
T

Thomas 'PointedEars' Lahn

I would prefer

function AList()
{

where no closure is needed.
This, of course, fails if AList has arguments that should be passed to List.

True, should be List.apply(this, arguments) if all arguments are to be
passed in the same order, or List.call(this, ...) if only certain arguments
are to be passed to the parent's constructor.
AList.prototype = clone(List.prototype);
[snip]

Search the archive for the clone (AKA inheritFrom) function and lots
of examples.

This may not be what the OP wants. If we use inheritFrom (misnamed in
my view) found in
http://devedge-temp.mozilla.org/toolbox/examples/2003/inheritFrom/inheritFrom.js

.... where the archive of this newsgroup is obviously _not_ located.
Also, the resource you are quoting is outdated and not authoritative.
====
we get what I call a 'static' copy of the properties of List.prototype.

Non sequitur.


PointedEars
 
J

Jorge

Hi everyone,
What I'm trying to achieve with the below code is
1. create a base 'class', called List
2. derive a 'class' from it called AList
3. derive another 'class' from AList, called BList, and then create
instances of both AList and BList()

The problem I have is that at step 3, when I create instances, the two
instances seem to share the same data, incorrectly. The blist()
variable at the end hasn't had anything added to it, yet it contains
what was added to the alist().

Can anyone could explain to me what I'm doing wrong ( tried something
like this on an ASP server running JScript, and using Firefox and both
give me the same results, so I'm guessing I'm misunderstanding this).

The only object with an own .items array is the Alist.prototype
object.
Alist instances have no own properties named .items : they inherit it
from the Alist.prototype object.
Blist instances have no own properties named .items : they inherit it
from the *empty* Blist.prototype object that in turn inherits it from
the same Alist.prototype object.
 
D

David Mark

David Mark wrote:

[snip]
var AList = function() {
   List.call(this);
};

This, of course, fails if AList has arguments that should be passed to List.

But there are none in this example, so it won't fail.
AList.prototype = clone(List.prototype);

[snip]

  > Search the archive for the clone (AKA inheritFrom) function and lots
of examples.

This may not be what the OP wants.  If we use inheritFrom (misnamed in
my view) found inhttp://devedge-temp.mozilla.org/toolbox/examples/2003/inheritFrom/inh...
====
function inheritFrom(/* Object */ aThis, /* Object */ aParent)
{
   var excp;

   for (var property in aParent)
   {
     try
     {
       aThis[property] = aParent[property];
     }
     catch(excp)
     {
     }
   }}

Not that.

[snip]
 
D

David Mark

I searched the internet (using Google) and took what came up first.

I just did a search for the newsgroup and the first entry was:
      Should we use 'new' or 'create' to create new objects
from last week.  It is a thread with 93 messages.

Doesn't really matter how many messages are in the thread.
Perhaps you'd show us how following your advice (search the newsgroup
archive for clone aka inherit from) would help the OP.

Searching for messages containing "clone" should do it. Don't worry
about how many messages are in the containing threads. I imagine
"inheritFrom" will yield Thomas' version of the desired function.
 
T

Thomas 'PointedEars' Lahn

Jonathan said:
Marcin said:
Hi everyone,
What I'm trying to achieve with the below code is
1. create a base 'class', called List
2. derive a 'class' from it called AList
3. derive another 'class' from AList, called BList, and then create
instances of both AList and BList()

The problem I have is that at step 3, when I create instances, the two
instances seem to share the same data, incorrectly. The blist()
variable at the end hasn't had anything added to it, yet it contains
what was added to the alist().

Can anyone could explain to me what I'm doing wrong
[snip]

function print(str) {
console.log(str + "<br>");
}
var List = function() {
this.items = [];
}
List.prototype.add = function( num ) {
this.items.push(num);
return this;
}
List.prototype.toString = function() {
return this.items.join(" -- ");
}

So far, so good. This is the usual way of doing this sort of thing.
var AList = function() {
}
AList.prototype = new List();

I think you are expecting AList to call List as part of its
initialisation. If you added (not tested):
List.apply(this, arguments)
to the body of AList, you'd get the desired result.

By coincidence, as `items' is not a prototype property. We've been over this.
The AList.prototype is an /initialised/ object that points to
List.prototype. So it has an 'items' property, which will be shared by
all 'instances' of AList.

I've said enough now, I think,
Correct.

to put you on the right track.

On the contrary.


PointedEars
 
D

David Mark

My previous group search was for inheritFrom, and as you can see it
didn't help.

No, IIRC, you found your own thread that has the function. What is
the problem?
So let's now try 'clone'.  The first hit is this message:http://groups.google.co.uk/group/comp.lang.javascript/msg/163dfb32ea1...

That search will certainly find the same thread (among many others.)
It starts by saying:
===
I assume this question must have been answered in the past, but I have
been searching the archives the last couple of days and cannot find a
solid answer to my problem.

I have a couple of properties that need to be created with every new
object created. To simplify, assume the only property I need to do
this with is called 'dom', which stores a dom object. In this context,
every object will need to create its own dom to avoid sharing of the
same dom object.
===

The poster is sound, and clearly not a newbie, and did not find the
answer to his question.

You are talking about some other poster from some other discussion.
I'd to improve our FAQ, so that more of these questions are answered.  I
don't like 'search the newsgroup' (for a keyword that is not obvious to
a newcomer) as an answer.  It our responsibility to move material from
the newsgroup to the FAQ (or to resources recommended by the FAQ).

Then bring it up with the FAQ maintainer.
 
M

Marcin

Hi everyone,
Apologies if my response seems delayed, I'm probably in a different
timezone and I'm doing this after work; also takes me some time to
play around with things to find how they work. I also want to thank
David Mark and Jonathan Fine for pointing out the points about the
prototype taking an _instantiated_ object and <function>.apply(this,
arguments) and <function>.call(this);

What I found worked was:

function List() {
this.items = [];
}

List.prototype = {
//methods
}

var AList = function() {
List.apply(this, arguments);
}
AList.prototype = new List();

var BList = function() {
AList.apply(this, arguments);
}

BList.prototype = new AList();

If that's correct, then I think I'm understanding this prototype
business finally; the List.prototype takes the object literal which
can be used to set up its basic methods and properties, the List
function can initialise those properties and make any calls necessary.
The <function>.apply(this, arguments) then initialises the values.
(And things can be overridden with the prototype or within the AList()
etc. functions)

The only real question is how is it that instanceof 'breaks' under
some styles of inheritance and not others; more to the point, how does
one ensure that if:
C is an object that inherits from B which is itself inherited from A

then
C instanceof B && instanceof A
is true ?

If I recall correctly, the David Crockford style of inheritance seemed
to break instanceof...

As for the other points raised.
1. I want to avoid the various clone() / inheritFrom() / create() /
extend() functions I've seen because at the very minimum they pollute
the namespace and look a little tacky for my taste. Secondly some of
them seem to break the instanceof operator.
The variant I found from John Resig didn't seem to work on the ASP
server we have...although I'm not sure that's because of differences
between JScript and ECMAscript or more probably, I didn't try hard
enough.

2. As for the 'class' vs 'prototype', oops, I miscommunicated. I did
intend to indicate I knew there was a difference, hence the quote
marks around the 'class', however for me the meanings are close enough
that context will determine the meaning; just like variable means the
same thing in any language regardless of whether it's strongly or
loosely typed, but I'll make a note to be more careful in the future.
For what it's worth, it did force me to go read up to make sure I know
of the difference.

3. I'm not sure what Jonathan meant by 'dynamic' and 'static' copy ?
Can I interpret it as 'not shared' and 'shared' copy; dynamic don't
share their properties, static do?

4. As to whether I searched thoroughly, I've been searching for quite
a while on the net for some explanation of this but I either didn't
grok it, found it used what I call the David Crockford style of doing
things (which I want to avoid), or found what I had originally posted,
which was evidently broken for what I wanted.

Thanks to everyone else who contributed. I certainly read it all and
found it helpful.

-Marcin
 
R

RobG

My previous group search was for inheritFrom, and as you can see it
didn't help.

So let's now try 'clone'.  The first hit is this message:http://groups.google.co.uk/group/comp.lang.javascript/msg/163dfb32ea1...

That may be the first hit, but it's not the oldest, try:

<URL: http://groups.google.com/group/comp.lang.javascript/msg/5d06e72e55d5bf11
Lasse Reichstein Nielsen has posted many versions over the years, but
they are all essentially the same code with different identifier
names.

Clone, and Crockford's beget(), have been well covered here and in
various blogs (including Crockford's own). Clone may well be a
suitable FAQ topic, even if the entry is just a summary with links to
clone() and beget() threads.

The definitive version is as posted at the link above, I think it
stems from a Richard Cornford post that I'd like to link to but GG
searching seems extremely limited lately.
 
D

David Mark

Hi everyone,
Apologies if my response seems delayed, I'm probably in a different
timezone and I'm doing this after work; also takes me some time to
play around with things to find how they work. I also want to thank
David Mark and Jonathan Fine for pointing out the points about the
prototype taking an _instantiated_ object and <function>.apply(this,
arguments) and <function>.call(this);

Constructed, not instantiated.
What I found worked was:

function List() {
  this.items = [];

}

List.prototype = {
 //methods

}

var AList = function() {
  List.apply(this, arguments);}

AList.prototype = new List();

No. You do not want a constructed List for the prototype of AList.
You want a clone of List.prototype.
var BList = function() {
  AList.apply(this, arguments);

}

BList.prototype = new AList();

Same here.
If that's correct, then I think I'm understanding this prototype
business finally; the List.prototype takes the object literal which
can be used to set up its basic methods and properties, the List
function can initialise those properties and make any calls necessary.

It may add or modify properties as needed (typically to suit the
arguments passed). In this case, it adds a single property (items),
regardless of the arguments.
The <function>.apply(this, arguments) then initialises the values.

It simply calls the function (another constructor here, but not called
as a constructor), setting the - this - identifier to the newly
constructed object and passing the arguments along (which has no
effect in this example.)
(And things can be overridden with the prototype or within the AList()
etc. functions)

Yes, you can modify the AList prototype and/or override List
properties in the AList constructor.
The only real question is how is it that instanceof 'breaks' under
some styles of inheritance and not others; more to the point, how does
one ensure that if:
C is an object that inherits from B which is itself inherited from A

then
C instanceof B && instanceof A
is true ?

In short, if instanceof breaks, you've fouled up the prototype chain.
But if it works as expected, it doesn't necessarily mean you haven't
fouled it up. Perhaps somebody else will be kind enough to diagram
these examples...
If I recall correctly, the David Crockford style of inheritance seemed
to break instanceof...

His name is Douglas and he has advocated more than one style of
inheritance. IIRC, at least one of them will break this operator.
As for the other points raised.
1. I want to avoid the various clone() / inheritFrom() / create() /
extend() functions I've seen because at the very minimum they pollute
the namespace and look a little tacky for my taste.

They do *not* pollute anything and the tackiness is unavoidable. It's
mot a perfectly thought out language in this regard, but attempts to
"fix" it have proven futile.
Secondly some of
them seem to break the instanceof operator.

The - clone - function, which I think is Lasse's will not break that
operator. The - inheritFrom - function is just Thomas' variation of -
clone - and I doubt it has that problem either. Disregard that
*other* inheritFrom, which was a red herring in this discussion.
The variant I found from John Resig didn't seem to work on the ASP

Don't waste time with Resig's examples.
server we have...although I'm not sure that's because of differences
between JScript and ECMAscript or more probably, I didn't try hard
enough.

No, JScript is an ECMAScript implementation, just like JavaScript(tm).

[snip]
3. I'm not sure what Jonathan meant by 'dynamic' and 'static' copy ?
Can I interpret it as 'not shared' and 'shared' copy; dynamic don't
share their properties, static do?

Disregard that other inheritFrom function. It isn't relevant to this
discussion.

[snip]
Thanks to everyone else who contributed. I certainly read it all and
found it helpful.

No problem. Seems you are almost there.
 
J

Jonathan Fine

Marcin said:
Hi everyone,
Apologies if my response seems delayed, I'm probably in a different
timezone and I'm doing this after work; also takes me some time to
play around with things to find how they work. I also want to thank
David Mark and Jonathan Fine for pointing out the points about the
prototype taking an _instantiated_ object and <function>.apply(this,
arguments) and <function>.call(this);

Thank you, Marcin, for asking a good question so nicely.
3. I'm not sure what Jonathan meant by 'dynamic' and 'static' copy ?
Can I interpret it as 'not shared' and 'shared' copy; dynamic don't
share their properties, static do?

Static:
a = {};
for (i in b)
a = b

Dynamic:
a = create(b)
where 'create(x)' creates an object whose prototype is 'x'.

Static:
Once the copy is made, changes in 'b' do not affect 'a'.

Dynamic:
Changes in 'b' do affect 'a' (unless masked by own-properties of 'a').

Note: In Python class inheritance is 'dynamic', not 'static'.

4. As to whether I searched thoroughly, I've been searching for quite
a while on the net for some explanation of this but I either didn't
grok it, found it used what I call the David Crockford style of doing
things (which I want to avoid), or found what I had originally posted,
which was evidently broken for what I wanted.

I'm sure you did a diligent search before posting, and please shrug off
any criticism from anyone who might say otherwise.

I'm glad you've found your participation on this newsgroup helpful.
 
D

David Mark

That may be the first hit, but it's not the oldest, try:

<URL:http://groups.google.com/group/comp.lang.javascript/msg/5d06e72e55d5bf11



Lasse Reichstein Nielsen has posted many versions over the years, but
they are all essentially the same code with different identifier
names.

Clone, and Crockford's beget(), have been well covered here and in
various blogs (including Crockford's own). Clone may well be a
suitable FAQ topic, even if the entry is just a summary with links to
clone() and beget() threads.

The definitive version is as posted at the link above, I think it
stems from a Richard Cornford post that I'd like to link to but GG
searching seems extremely limited lately.

Ain't that the truth. Different wheels fall off this clunker every
week.
 
T

Thomas 'PointedEars' Lahn

kangax said:
What does "need for closure" have to do with the choice of using
/FunctionDeclaration/ over /FunctionExpression/?

var AList = (function() {
var foo = 42;

return function(x) {
return foo * x;
};
})();

You cannot have that with

function AList()
{
// ...
}


PointedEars
 
J

Jorge

  var AList = (function() {
    var foo = 42;

    return function(x) {
      return foo * x;
    };
  })();

You cannot have that with

  function AList()
  {
    // ...
  }

Two wrongs don't make a right.
 
G

Garrett Smith

RobG said:
That may be the first hit, but it's not the oldest, try:

<URL: http://groups.google.com/group/comp.lang.javascript/msg/5d06e72e55d5bf11

Lasse Reichstein Nielsen has posted many versions over the years, but
they are all essentially the same code with different identifier
names.

Clone, and Crockford's beget(), have been well covered here and in
various blogs (including Crockford's own). Clone may well be a
suitable FAQ topic, even if the entry is just a summary with links to
clone() and beget() threads.

Links seems better; explanation of the prototype chain, scope, and
inheritance techniques are too involved for the FAQ.

Maybe:

How can I clone an object?
* LRN clone method/ link to article [link]
* link to cloning using |for in| borrowing [link]

How does inheritance work?
javascript uses prototype inheritance, [link]
members can be hidden using Scope [link]

If those questions are sufficient, and the answer format is sufficient,
then pick best articles need to be picked and linked to by replacing
"[link]" with an actual link.
The definitive version is as posted at the link above, I think it
stems from a Richard Cornford post that I'd like to link to but GG
searching seems extremely limited lately.

Google is in the search business and the google main search feature
works. I wonder why the groups search fails so often. Google groups'
search *should* work and I think that ought to be a high priority.

I am not aware of any public bugtracker for Google. They ought to have
one that allows users to vote on bugs. Would be a fair QA idea, since
current QA techniques are failing.

Garrett
 

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,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top