Variables in TclOO

Difference between version 4 and 5 - Previous - Next
** Variables in TclOO **

*** Variable Commands ***

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

   * `'''::[variable]''' ''name''`
   * `'''::[variable]''' ''?name value?'' ''?...?''`

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.

   * `'''::[oo::objdefine]''' ''$object'' '''variable''' ''?-slotOperation?'' ''?name ...?''`

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`.

   * `'''[my] variable''' ''?name ...?''`
   * `'''::[oo::object] variable''' ''?name ...?''`

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 **

   * [Inspecting TclOO]
   * [TclOO]
   * http://www.magicsplat.com/articles/oo.html%|%APN's excellent TclOO Article%|% which calls these "data members"

<<categories>>TclOO