I stumbled over the variable scope when inheriting a class with TclOO. The member variable nCrumbs below is not visible to the inherited class without repeating the declaration.
Is there a way to avoid replicating all the variable declarations from the superclass?
(I read through all the OO documentation, specifically oo::define and oo::object, also the non-exported stuff, googled for it. There are so many concepts to get around various things, I got lost. I am looking for something that keeps the inherited class as simple as possible. The superclass may have any fancy complicated code in it, though.)
Any help would be greatly appreciated, thanks.
oo::class create toaster {
variable nCrumbs; #declaration
constructor {} {
set nCrumbs 0; #definition
}
method toast {nSlices} {
if {$nCrumbs > 50} {
error "== FIRE! FIRE! =="
}
set nCrumbs [expr $nCrumbs+4*$nSlices]
}
method clean {} {
set nCrumbs 0
}
}
oo::class create smartToaster {
superclass toaster; #inherit
variable nCrumbs; #<======= have to declare again
method toast {nSlices} {
if {$nCrumbs > 40} {
my clean
}
next $nSlices; #call superclass method
}
}
set clsToaster [smartToaster new]
$clsToaster toast 2
The variable is physically located (if you can say that for code) in a private namespace for the object instance. By doing
variable
in the declaration, you are directing the method bindings to merely make it available without further commands.But yes, subclasses have to use
variable
as well to see it by default, or to use one of the standard Tcl variable scope management commands, e.g.,upvar
ornamespace upvar
, or even the privatevariable
method.It didn't used to be that way, but it was found to be just too confusing otherwise; the variable declarations for a class only affect the methods of that class, not its subclasses.
[EDIT]: It is possible to make a parent's variables also visible in the child via appropriate metaclass magic:
Demonstrating this:
While I don't in general recommend this as it makes a subclass much more fragile when a superclass evolves, and it doesn't track any changes to the superclass, it's easy to set up with a little scripting. You just delegate the smartness to your own metaclass and use that to construct all your operational classes (which are purely conventional TclOO classes from there on).
Donal, thanks for answering.
So I am assuming there is no mechanism available by default to make all the superclass variables available.
My current solution is to collect all variable names and then declare them with one single call. Yet, I have to repeat this in every method. I would want to put the declareSuperclassVars outside the methods. Is this possible somehow? Perhaps with another approach?
Thanks