Variables in TclOO

Variables in TclOO

Variable Commands

There are at least three commands in Tcl 8.5+ named variable. They are:

Makes a namespace variable visible in the current scope.

  • '::oo::define $class variable' ?-slotOperation? ?name ...?

Makes an instance variable visible in all methods defined in the current class.

Makes an instance variable visible in all methods defined on the object. This can be thought of as a special case of ::oo::define::variable.

Makes an instance variable visible in the current scope. This is an unexported method of ::oo::object, and equivalent to the following definition:

oo::define oo::object method variable {args} {
    foreach var $args {
        uplevel 1 [
            list namespace upvar [namespace current] $var $var
        ]
    }
}
oo::define oo::object unexport variable

Another utility method on oo::object is (almost-)equivalently defined as:

oo::define oo::object method varname {name} {
    return [namespace current]::$name
}

Where are my variables?

Instance variables are just namespace variables in the object's namespace. So, inside a method:

my variable foo
variable foo

both have the same effect. They differ importantly in how multiple arguments are treated, so be careful. One might prefer to use my variable in methods, as it more closely resembles oo::define variable.

oo::define and oo::objdefine arrange that the variable is automatically made visible in all methods defined at the same level. This is similar to having variable name implicitly prepended to the methods' bodies.

"At the same level" means simply that object variables are made visible in object methods (both defined with oo::objdefine), and class variables are made visible in methods on the same class (ie: not superclasses, subclasses or mixins).

Choose Good Names

When using inheritance or mixins, it's important to be aware that while ::oo::define variable only makes a variable visible to methods in the current class, the variable will exist in the object's namespace. Thus collisions are possible, so beware:

oo::class create S {
    variable x
    method sx {} {
        set x 0
    }
}
oo::class create M {
    variable x
    method mx {} {
        incr x 3
    }
}
oo::class create C {
    superclass S
    mixin M
    variable x
    method cx {} {
        incr x 5
    }
}

C create t
puts [list [t sx] [t cx] [t mx] [t sx] [t cx] [t mx]]
# => 0 5 8 0 5 8

This sort of collision might be harmful if the author of C is unaware that M uses the name x for its own purposes. Thus, if you're publishing a class to use as a superclass or a mixin, the variables it uses should be considered part of the specification.

For "private" data, short and likely-to-collide names should be avoided. It might be a good idea to contain it in a uniquely-named array or sub-object. Or perhaps a dict, or a coroutine!

RZ or have a look on TclOO private variables

DKF 8.7 has a private variable declaration. That uses variable name rewriting (using names unlikely to be hit by accident).

See Also