Tobie Langel
2006-Oct-25 03:43 UTC
Bug ? Different instances of an object created through Class.create() share the same Array Object
Hi all,
Noticed the following while working on a script:
var Tester = Class.create();
Tester.prototype = {
initialize: function(element) {
this.array[0] = element;
},
array: []
}
var t1 = new Tester(''hello'');
var t2 = new Tester(''world'');
console.log(t1.array.inspect()) // returns [''world'']
console.log(t2.array.inspect()) // returns [''world'']
For those equipped with Firebug (and therefore Firefox) there''s a
live version here: http://tobielangel.com/code/test.html which will
print the arays'' values to your console.
This issue/bug is due to the fact that both arrays actually reference
the same Array object.
The following will yield the expected outcome (because the array is
actually created during initialization):
var Tester = Class.create();
Tester.prototype = {
initialize: function(element) {
this.array = [];
this.array[0] = element;
}
}
var t1 = new Tester(''hello'');
var t2 = new Tester(''world'');
console.log(t1.array.inspect()) // returns [''hello'']
console.log(t2.array.inspect()) // returns [''world'']
In my opinion, this is a bug. I''m not too familiar with the way Class
functions, but it looks like some Object + array cloning should be
applied at some point.
Any suggestions ?
Regards,
Tobie
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Spinoffs" group.
To post to this group, send email to
rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-spinoffs
-~----------~----~----~----~------~----~------~--~---
Christophe Porteneuve
2006-Oct-25 06:20 UTC
Re: Bug ? Different instances of an object created through Class.create() share the same Array Object
Tobie Langel a écrit :> var Tester = Class.create(); > Tester.prototype = { > initialize: function(element) { > this.array[0] = element; > }, > array: [] > }This is nominal. Your array field is in the PROTOTYPE. If you want to make an awkward OOP-based comparison, it''s a STATIC CLASS MEMBER. So of course your instances share it. -- Christophe Porteneuve a.k.a. TDD "[They] did not know it was impossible, so they did it." --Mark Twain Email: tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs -~----------~----~----~----~------~----~------~--~---
Tobie Langel
2006-Oct-25 06:28 UTC
Bug ? Different instances of an object created through Class.create() share the same Array Object
Hi Christophe, What bothers me is the fact that in the following case, two instances of the Tester class would NOT share the same string.>> var Tester = Class.create(); >> Tester.prototype = { >> initialize: function(str) { >> this.string = str; >> }, >> string: '''' >> }In that case, this.string would just be an instance property, wouldn''t it? regards, Tobie On 25 oct. 2006, at 02:20, Christophe Porteneuve wrote:> > Tobie Langel a écrit : >> var Tester = Class.create(); >> Tester.prototype = { >> initialize: function(element) { >> this.array[0] = element; >> }, >> array: [] >> } > > This is nominal. Your array field is in the PROTOTYPE. If you > want to > make an awkward OOP-based comparison, it''s a STATIC CLASS MEMBER. > So of > course your instances share it. > > -- > Christophe Porteneuve a.k.a. TDD > "[They] did not know it was impossible, so they did it." --Mark Twain > Email: tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs -~----------~----~----~----~------~----~------~--~---
tobie
2006-Oct-25 06:30 UTC
Re: Bug ? Different instances of an object created through Class.create() share the same Array Object
That''s not very consistent really. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs -~----------~----~----~----~------~----~------~--~---
Christophe Porteneuve
2006-Oct-25 07:14 UTC
Re: Bug ? Different instances of an object created through Class.create() share the same Array Object
Hey Tobie, Ah, I should have waited for breakfast caffeine to sink in before answering you, sorry :-) Prototype-defined fields are *not* static fields /per se/. You would have to work on the constructor function''s prototype to obtain something along those lines. The issue you run into here is due to how prototypes are used by the new operator. Basically, every instance refers, by default, to the properties defined in the prototype, dynamically. It''s like they automatically proxy-delegate to the prototype, with the "this" binding going on for methods. Don''t forget that object variables are just references. If you do this in JavaScript: var a = [1, 2, 3]; var b = a; a[1] = ''X''; Then b will become [1, ''X'', 3]. The "b = a" expression just copies a pointer, so to speak. Both variables reference the same object. It''s fortunate that prototypes work this way, otherwise each instance would hold, for instance, a distinct copy of all methods and fields defined in the prototype. Which would be a pretty bad way to go about defining methods. When you want per-instance fields that are still object references, you need to assign them to "this."-prefixed properties in the initialize function (called at construction time, see Class.create). This way, each "new", calling initialize, will use a fresh value (i.e. a fresh object) for its field, therefore a unique reference. Look into Prototype and script.aculo.us code: you''ll see that all prototype-defined fields are basically used as constants (e.g. the NODEMAP and ATTR_MAP fields in Builder). All per-instance fields are assigned, directly or indirectly, from the initialize functions. As for this code: Tobie Langel a écrit :>>> var Tester = Class.create(); >>> Tester.prototype = { >>> initialize: function(str) { >>> this.string = str; >>> }, >>> string: '''' >>> }The last string definition is useless: it''s going to be overridden locally by every instance, because of the initialize function, that guarantees each instance has its own reference. I hope this makes it a bit clearer. -- Christophe Porteneuve aka TDD tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs -~----------~----~----~----~------~----~------~--~---
Tobie Langel
2006-Oct-25 07:24 UTC
Re: Bug ? Different instances of an object created through Class.create() share the same Array Object
Thanks for clearing it up, it makes more sense like this. So this should be considered as a feature of JavaScript rather than a Prototype bug. I spent about half a day debugging a Class because of that feature... ;-) Regards, Tobie On 25 oct. 2006, at 03:14, Christophe Porteneuve wrote:> > Hey Tobie, > > Ah, I should have waited for breakfast caffeine to sink in before > answering you, sorry :-) > > Prototype-defined fields are *not* static fields /per se/. You would > have to work on the constructor function''s prototype to obtain > something > along those lines. > > The issue you run into here is due to how prototypes are used by > the new > operator. Basically, every instance refers, by default, to the > properties defined in the prototype, dynamically. It''s like they > automatically proxy-delegate to the prototype, with the "this" binding > going on for methods. > > Don''t forget that object variables are just references. If you do > this > in JavaScript: > > var a = [1, 2, 3]; > var b = a; > a[1] = ''X''; > > Then b will become [1, ''X'', 3]. The "b = a" expression just copies a > pointer, so to speak. Both variables reference the same object. > > It''s fortunate that prototypes work this way, otherwise each instance > would hold, for instance, a distinct copy of all methods and fields > defined in the prototype. Which would be a pretty bad way to go about > defining methods. > > When you want per-instance fields that are still object references, > you > need to assign them to "this."-prefixed properties in the initialize > function (called at construction time, see Class.create). This way, > each "new", calling initialize, will use a fresh value (i.e. a fresh > object) for its field, therefore a unique reference. > > Look into Prototype and script.aculo.us code: you''ll see that all > prototype-defined fields are basically used as constants (e.g. the > NODEMAP and ATTR_MAP fields in Builder). All per-instance fields are > assigned, directly or indirectly, from the initialize functions. > > As for this code: > > Tobie Langel a écrit : >>>> var Tester = Class.create(); >>>> Tester.prototype = { >>>> initialize: function(str) { >>>> this.string = str; >>>> }, >>>> string: '''' >>>> } > > The last string definition is useless: it''s going to be overridden > locally by every instance, because of the initialize function, that > guarantees each instance has its own reference. > > I hope this makes it a bit clearer. > > -- > Christophe Porteneuve aka TDD > tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs -~----------~----~----~----~------~----~------~--~---
Ryan Gahl
2006-Oct-25 14:27 UTC
Re: Bug ? Different instances of an object created through Class.create() share the same Array Object
It''s not just a feature of Javascript... having to initialize instance
level
members in a class''s construction is a characteristic of not only
javascript, but any object oriented language I''ve ever seen. For
instance,
you can define a publically accessible property on a class in java or c#,
but for the property getter method to be able to return a valid object
reference at any point in the life of that object, you will have had to have
set it to a valid object reference at some point prior to that, and usually
you''d do that via initializing it during construction. This also has
the
added benefit of not allocating that memory until it''s needed. In your
js
example you are assuming that there is magically going to be a new array
allocated in memory, without you having to explicitly create one. The
confusion can be expected though, since you can call methods of the
prototype using this.someMethod(), and the "this" inside that method
will
refer to your instance, so it''s natural to equate that to the classical
model where each instance has it''s own copy of that method... however
you
are still calling the prototype''s method (there wasn''t a new
method copied
into memory for your instance, it''s just that your instance was bound
as the
callee to the prototype''s method). That''s the main difference
between js''s
prototypical OO and the classical OO you''re used to. All js object
instances
are sharing any access to their prototype''s properties/members (be it
methods or arrays or whatever).
In a language like java or c#, you CAN define a class like the following
pseudo-code, and it will work as you were expecting your javascript to work.
Just keep in mind though that the compilation step in those other languages
handles delegating the initialization of those variables to the
object''s
internal constructor.
<pseudocode>
class someJavaOrC#Class
{
//leaving out actual getter/setter stuff for pseudo-code purposes
public Array myArray = new Array();
//constructor
public someJavaOrC#Class(string someInitialString)
{
myArray[0] = someInitialString;
}
}
</pseudocode>
On 10/25/06, Tobie Langel
<tobie.langel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
wrote:>
>
> Thanks for clearing it up, it makes more sense like this.
>
> So this should be considered as a feature of JavaScript rather than a
> Prototype bug.
>
> I spent about half a day debugging a Class because of that
> feature... ;-)
>
> Regards,
>
> Tobie
>
>
> On 25 oct. 2006, at 03:14, Christophe Porteneuve wrote:
>
> >
> > Hey Tobie,
> >
> > Ah, I should have waited for breakfast caffeine to sink in before
> > answering you, sorry :-)
> >
> > Prototype-defined fields are *not* static fields /per se/. You would
> > have to work on the constructor function''s prototype to
obtain
> > something
> > along those lines.
> >
> > The issue you run into here is due to how prototypes are used by
> > the new
> > operator. Basically, every instance refers, by default, to the
> > properties defined in the prototype, dynamically. It''s like
they
> > automatically proxy-delegate to the prototype, with the
"this" binding
> > going on for methods.
> >
> > Don''t forget that object variables are just references. If
you do
> > this
> > in JavaScript:
> >
> > var a = [1, 2, 3];
> > var b = a;
> > a[1] = ''X'';
> >
> > Then b will become [1, ''X'', 3]. The "b =
a" expression just copies a
> > pointer, so to speak. Both variables reference the same object.
> >
> > It''s fortunate that prototypes work this way, otherwise each
instance
> > would hold, for instance, a distinct copy of all methods and fields
> > defined in the prototype. Which would be a pretty bad way to go about
> > defining methods.
> >
> > When you want per-instance fields that are still object references,
> > you
> > need to assign them to "this."-prefixed properties in the
initialize
> > function (called at construction time, see Class.create). This way,
> > each "new", calling initialize, will use a fresh value (i.e.
a fresh
> > object) for its field, therefore a unique reference.
> >
> > Look into Prototype and script.aculo.us code: you''ll see that
all
> > prototype-defined fields are basically used as constants (e.g. the
> > NODEMAP and ATTR_MAP fields in Builder). All per-instance fields are
> > assigned, directly or indirectly, from the initialize functions.
> >
> > As for this code:
> >
> > Tobie Langel a écrit :
> >>>> var Tester = Class.create();
> >>>> Tester.prototype = {
> >>>> initialize: function(str) {
> >>>> this.string = str;
> >>>> },
> >>>> string: ''''
> >>>> }
> >
> > The last string definition is useless: it''s going to be
overridden
> > locally by every instance, because of the initialize function, that
> > guarantees each instance has its own reference.
> >
> > I hope this makes it a bit clearer.
> >
> > --
> > Christophe Porteneuve aka TDD
> > tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org
> >
> > >
>
>
> >
>
--
Ryan Gahl
Application Development Consultant
Athena Group, Inc.
Inquire: 1-920-955-1457
Blog: http://www.someElement.com
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Spinoffs" group.
To post to this group, send email to
rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-spinoffs
-~----------~----~----~----~------~----~------~--~---
tobie
2006-Oct-26 03:40 UTC
Re: Bug ? Different instances of an object created through Class.create() share the same Array Object
Hi Ryan, Thanks for clearing this up. You''ve been really helpful. Regards, Tobie --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs -~----------~----~----~----~------~----~------~--~---