Possible bug with arrays and classes

14 views
Skip to first unread message

kstubs

unread,
Aug 31, 2011, 3:49:10 PM8/31/11
to prototype-s...@googlegroups.com
It seems that the collection array is growing for each instance of foo and bar class.  I would expect that the collection array contains 1 item for each instance.  What is wrong?  Is this a bug, or expected results?

Karl..

My Test Code:

var base = Class.create({
    collection: [],
    itterations:0,
    initialize: function() {
        this.itterations++;
        this.collection.push(this.itterations);
        console.log('Itterations: %s, Number items in Collection: %s', this.itterations, this.collection.size());
    }
});

var foo = Class.create(base, {});
var bar = Class.create(base, {});

var _foo = new foo(); // expecting ==> Itterations: 1, Number items in Collection: 1
var _bar = new bar(); // expecting ==> Itterations: 1, Number items in Collection: 1

// _foo is correct, but Actual results for _bar ==> Itterations: 1, Number items in Collection: 2

kstubs

unread,
Aug 31, 2011, 6:49:02 PM8/31/11
to prototype-s...@googlegroups.com
This seems to work, declaring the array new in the initialize event.  Would love to find out if this behavior is expected or not.  Seems like an issue, but then there is always the chance that some jscript guru explains the reason for this.

var base = Class.create({
    collection: [],
    itterations:0,
    initialize: function(item) {
        this.itterations++;
        this.collection = new Array();
        this.collection.push(item);
        console.log('Itterations: %s, Number items in Collection: %s', this.itterations, this.collection.size());
    }
});

var foo = Class.create(base, {});
var bar = Class.create(base, {});

var _foo = new foo('foo'); // expecting ==> Itterations: 1, Number items in Collection: 1
var _bar = new bar('bar'); // expecting ==> Itterations: 1, Number items in Collection: 1

// Actual results for _bar ==> Itterations: 1, Number items in Collection: 2

Victor

unread,
Sep 1, 2011, 2:38:32 AM9/1/11
to prototype-s...@googlegroups.com
I think it should look like

var base = Class.create({
    iterations: 0,
    initialize: function(item) {
        this.iterations++;
        //this.collection = [];
        this.collection.push(item);
        console.log('Iterations: %s, Number items in Collection: %s', this.iterations, this.collection.size());
    }
});
var foo = Class.create(base, {
  collection: []
});
var bar = Class.create(base, {
  collection: []
});


Collection in your sample was actually base.prototype.collection and was shared by all child classes and instances.

kstubs

unread,
Sep 1, 2011, 3:40:34 AM9/1/11
to prototype-s...@googlegroups.com
Hmm, ok I'll try that.  How do you avoid base.prototype similar issues to what I've just experienced?  I about panicked, I am developing a fairly large chart stock application and when things started to go south, I found this issue.

Karl..

Victor

unread,
Sep 1, 2011, 3:59:24 AM9/1/11
to prototype-s...@googlegroups.com
It's kinda feature, not issue ;) You expect that method references in base.prototype will be visible in child classes, and array reference behaves similarly.

T.J. Crowder

unread,
Sep 1, 2011, 5:54:02 AM9/1/11
to Prototype & script.aculo.us
Hi,

> My Test Code:
>
> var base = Class.create({
>     collection: [],
>     itterations:0,
>     initialize: function() {
>         this.itterations++;
>         this.collection.push(this.itterations);
>         console.log('Itterations: %s, Number items in Collection: %s',
> this.itterations, this.collection.size());
>     }
>
> });

What that does is create a constructor function where `collection` is
shared by all instances created by the function, because `collection`
is part of the constructor's prototype. This is correct behavior. It
happens because you never assign to `collection` via one of your
instances, so the instances (including the ones that are the
prototypes for `foo` and `bar`) continue to use the prototype's copy.
It's the same mechanism that allows function objects to be shared. (It
would happen if collection were some other kind of object reference,
too.) In class-based OOP you'd think of it as being a class member.

> var foo = Class.create(base, {});
> var bar = Class.create(base, {});

Your derived constructor functions also share `collection` because
they're using it from the base constructor's prototype, too. There is
only one `collection` array in total, no matter how many derived
constructors or new instances you create. (There's no real analogue in
class-based OOP here, I don't think. Prototypical OOP is just
different sometimes.)

Victor's solution moves `collection` to the `foo` and `bar`
constructor function prototypes instead, and so all `foo` instances
will share the `foo` constructor's collection, and all `bar` instances
will share the `bar` constructor's collection. If that's what you
meant, great.

But if you want each *instance* to have its own collection, which is
the normal use-case, initialize `collection` in the `initialize`
function:

var base = Class.create({
    itterations:0,
    initialize: function() {
this.collection = [];
        this.itterations++;
        this.collection.push(this.itterations);
        console.log('Itterations: %s, Number items in Collection: %s',
this.itterations, this.collection.size());
    }
});

Now you may be thinking: But why did he move `collection` but not
`itterations`? (BTW, just the two "t"s in that, rather than
three. ;-) ) We don't assign to `itterations` either, do we? Actually
we do:

this.itterations++;

It doesn't look like an assignment, but it basically means:

this.itterations = this.itterations + 1;

...and so it creates an "own" copy of the property on the instance,
rather than incrementing the one on the prototype. (Subtle, that one,
and I had to go check to be sure.)

Happy coding,
--
T.J. Crowder
Independent Software Engineer
tj / crowder software / com
www / crowder software / com

kstubs

unread,
Sep 1, 2011, 11:28:26 AM9/1/11
to prototype-s...@googlegroups.com
OK, I'm thinking this all makes sense!  No I get it.. and I do recall reading something like this a long time ago, it just didn't register then
Thank you Victor, thank you T.J. for code examples and excellent explanations.

Karl..
Reply all
Reply to author
Forward
0 new messages