This is somewhat similar to this question TclOO Variable Scope with Inheritance/superclass, but I would like to make a number of variables available to the methods in my class, and which ones and how many those are is determined dynamically at runtime. Pseudocode:
oo::class create myClass {
constructor {registryObject} {
foreach variable [$registryObject getVariables] {
<make $variable visible to all methods>
}
method useVariable{} {
<do something with previously declared variable>
}
}
is there any way to achieve this without another layer of indirection? The problem is that the registryObject gives me a variable number of references to other objects, which I would like to be accessible in derived classes. As with the question referenced above, the point here is brevity in the code of a derived class. I am willing to use dirty and complicated hacks in the superclass if neccessary.
It's going to be really hard to do exactly what you're asking for.
The variable
class declaration used in TclOO adjusts how Tcl resolves variables in (normal class-defined) methods declared in the same class. It does not affect methods defined by superclasses, subclasses or instances (which should use their own variable
declarations if they want them). The variables themselves are visible though — all variables associated with an instance are variables in the current namespace while the object is executing (which is instance-specific) — they just have to be brought in explicitly.
If the response to the registry object query was being used to dynamically create instance methods, you could do it:
constructor {registryObject} {
foreach variable [$registryObject getVariables] {
oo::objdefine [self] variable $variable
}
oo::objdefine [self] method foo {...} {
# This method *will* have automatic access
}
}
Yes, the method is created inside the constructor (and it doesn't make much sense to create the methods on the class). No, most other object systems don't have instance methods. Think of it as being a bit like giving each instance its own special little class. (That's not what happens, but it's not too far off.)
If you were going to create the methods for all instances of the class, it makes sense to do so either during the creation of the class (boring, conventional!) or during the creation of the first instance of the class, assuming the registry does the sensible thing and gives the same answer for all instances of that class. If that's the case, you could do it. Overriding the create
and new
methods is probably the simplest way to do it:
oo::class create myClass {
self method create {name registryObject} {
foreach var [$registryObject getVariables] {
oo::define [self] variable $var
}
next $name $registryObject
}
self method new {registryObject} {
foreach var [$registryObject getVariables] {
oo::define [self] variable $var
}
next $registryObject
}
constructor ...
method ...
}
It's a bit slow to do it this way because each object creation will trigger recompilation of lots of things, but it ought to work.
Or you could do it in the constructor; I think it's less elegant but you might disagree:
constructor {registryObject} {
oo::define [self class] variable {*}[$registryObject getVariables]
}
I think both of these options are not good ways to do it and I recommend doing the registry lookup during class creation. Or making the methods not rely on the variable
mechanism, instead using my variable
(very much like global
but for instance variables) to access the variables they need.
If only I could figure out more exactly what the bigger picture was, I could help you better…