logo       

The shared variable problem: msg#00018

web.kupu.devel

Subject: The shared variable problem

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>
Google Custom Search

News | FAQ | advertise