|
The shared variable problem: msg#00018web.kupu.devel
Guido and I have been discussing the issue about Kupu classes sometimes sharing variables. This is likely to become significant in the future as I want to see if I can do a Plone implementation which has multiple genuinely separate instances of Kupu. It became clear that the problem is quite subtle, so I thought I would write up what I think is the problem (and the solution). Here is some code which demonstrates the problem: function MyBase() { this.bar = []; } function MyClass1() { this.foo = []; } function MyClass2() { this.foo = []; } MyClass1.prototype = new MyBase; MyClass2.prototype = new MyBase; var a = new MyClass1(); var b = new MyClass1(); var c = new MyClass2(); a.foo.push('foo'); a.bar.push('bar'); println("a.foo="+a.foo); println("b.foo="+b.foo); println("c.foo="+c.foo); println("a.bar="+a.bar); println("b.bar="+b.bar); println("c.bar="+c.bar); The output from running this program (I have a JS environment where println outputs a line of text): a.foo=foo b.foo= c.foo= a.bar=bar b.bar=bar c.bar= MyClass1 and MyClass2 have a common base class MyBase and as you can see the bar member is shared between instances of the same class, but not shared across classes with a common base. The problem: Any variable assigned to 'this' in the base class constructor becomes a class variable in the subclasses: but is NOT shared between different subclasses (if I further subclasses MyClass1 then subclasses of MyClass1 would also share the same instance as MyClass1 itself). This probably isn't what we want, since if we want a class variable we could create it by assigning to MyBase.prototype.bar. The solution, it seems to me, is that we need to ensure that the base class constructor is called whenever an instance of a derived class is constructed. Javascript won't do this automatically, but it is easy enough to do it manually. (For anyone reading this who doesn't know Ecmascript backwards: apply is a method of all functions which allows you to call the function with an explicit 'this' value. If the function takes parameters these are simply specified after the 'this' value.) function MyBase() { this.bar = []; } function MyClass1() { MyBase.apply(this); this.foo = []; } function MyClass2() { MyBase.apply(this); this.foo = []; } MyClass1.prototype = new MyBase; MyClass2.prototype = new MyBase; var a = new MyClass1(); var b = new MyClass1(); var c = new MyClass2(); a.foo.push('foo'); a.bar.push('bar'); println("a.foo="+a.foo); println("b.foo="+b.foo); println("c.foo="+c.foo); println("a.bar="+a.bar); println("b.bar="+b.bar); println("c.bar="+c.bar); With the addition of the two explicit calls to the base constructor we get the following output showing that bar is no longer shared: a.foo=foo b.foo= c.foo= a.bar=bar b.bar= c.bar= N.B. I thought for a bit that calling this.constructor.apply(this) would call the base class constructor successfully, but this only works for a single level of base/derived classes. To ensure that all base class constructors get called you need to name the base class explicitly in the call. I'll trawl through the files and see if I can fix all the classes so they call their base classes explicitly. Hopefully this will result in a slight reduction in code size (since some duplicate initialisation will go away), but it isn't quite a trivial exercise since the KupuTool > KupuButton > KupuStateButton > KupuRemoveElementButton hierarchy bizarrely has constructor parameters in the base classes which aren't also in the derived classes. |
|
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| Previous by Date: | Re: post-XSLT whitespace: 00018, Guido Wesdorp |
|---|---|
| Next by Date: | Re: The shared variable problem: 00018, yuppie |
| Previous by Thread: | post-XSLT whitespacei: 00018, Izaak Branderhorst |
| Next by Thread: | Re: The shared variable problem: 00018, yuppie |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |