I’ll go a bit out on a limb, since I’m not sure exactly where the confusion is. But maybe this will illuminate a bit.
Maybe this is what I shouldn’t do : I’m trying to take advantage of the Class being a single Object that can hold datas.
There’s nothing wrong with this. The things are: how to initialize the classvars, and how to access them.
- Initializing:
*initClass
is the right way. If a classvar will hold a simple literal value (integer, float, string, symbol), then you could do without initClass, but any objects have to be assigned within initClass.
GM {
classvar <aFloat = 1.0; // this is OK
// this is not OK!
// classvar <aColor = Color(0.5, 1, 0.2);
classvar <aColor;
*initClass {
aColor = Color(0.5, 1, 0.2);
}
}
- Accessing: The
<
in <aColor
has created a method *aColor { ^aColor }
belonging to the class GM – not to instances.
GM.findMethod(\aColor)
-> nil
This is empty! Because it’s looking for an instance method, and there isn’t one.
Meta_GM.findMethod(\aColor)
-> Meta_GM:aColor
There it is.
This means, outside of the class GM, the only way to get to aColor is GM.aColor
– to call aColor
on the class itself.
Where it perhaps gets a little confusing is that instance methods defined within GM can use aColor directly. This is a matter of variable scope, not of any methods.
GM {
classvar <aFloat = 1.0; // this is OK
// this is not OK!
// classvar <aColor = Color(0.5, 1, 0.2);
classvar <aColor;
*initClass {
aColor = Color(0.5, 1, 0.2);
}
okMethod {
// direct access within a method:
// aColor is within the {} scope where classvar aColor exists
aColor.postln
}
notOkMethod {
this // access the instance
.aColor // this method doesn't exist for the instance!
.postln
}
}
Then:
a = GM.new;
a.okMethod
Color(0.5, 1, 0.2)
-> a GM
a.notOkMethod
^^ ERROR: Message 'aColor' not understood.
RECEIVER: a GM
In notOkMethod, it doesn’t matter that this is within the variable scope – this.aColor
is asking to perform a method that doesn’t exist.
But if it were anotherOkMethod { this.class.aColor.postln }
, then it would be fine – because this is replacing the instance with its class as the receiver of the message aColor
.
So it’s necessary to distinguish between variable access (which depends on scoping rules) and message sending.
Instances
Jordan’s first example has a parent class with a classvar mainColor, and a subclass of it with its own classvar mainColor.
These are two variable declarations – so there are two variables… with the same name. This means GMUserVIew cannot access the parent’s variable through variable scoping (though it it can get it using GM.mainColor
). My preference would be to avoid duplicating classvar names between parent and child classes.
The second example is fine, where the subclass has an instance variable (which users could change, per instance).
The super.new
thing – for any new object to be created, it eventually has to go through Object *new
or *newCopyArgs
. These are, to my knowledge, the only methods in the entire class library that create the object instance – this means it is impossible for any instances of anything to exist, ever, without going through one of these methods! super.new
pushes execution up through the class tree until it reaches Object.
The thing about super
it isn’t obvious at first is that it dispatches the method call through the superclass, but within the superclass method, this
is still the child class! This is necessary for Object to know how many slots to allocate. Then, this means that init
at every level will call the child init
method… maybe you don’t need to deal with this yet, just be aware of it for now.
hjh