Search code examples
variablestclitcl

difference between uninitialized and initialized class variable in itcl


I have used the following two versions of a class variable:

::itcl::class Subcase {
    variable _id
}

and

::itcl::class Subcase {
    variable _id    -1
}

Obviously, the only apparent difference, is that the former does not have an initial value. When I use my Accessor, which is defined as:

public method ::hwascii::Subcase::Id {{newValue __keep__}} { if {$newValue != "__keep__"} { set _id $newValue }; return [set _id] }

to first set and then get back that value, I will get two different behaviours, depending on which version above I have used to declare the variable. In the first uninitialized case, the accessor will always throw:

can't read "_id": no such variable

but with the second declaration, it will work as expected and return either the initial value, or if it has been changed, that new value.

Note1: Setting the value through my accessor always works.

s info variable _id

will report either

protected variable ::hwascii::Subcase::_id -1 42

or

protected variable ::hwascii::Subcase::_id <undefined> 42

depending on whether I have the initialized version or not.

Note2: The accessor is a one liner, because it is generated in a proc, which uses concat and uplevel to generate a kind of "default" accessor.

Note3: My Version of tcl is 8.5 My Version of itcl is 3.4 both cannot be changed

Question: I have a working solution now, but would like to understand what the difference is. A good explanation will answer my question, a pointer to a good documentation would also be nice, but obvisously a link to:

http://www.tcl.tk/man/tcl8.6/Itcl4.0.0Cmd/class.htm#M22

or even more general will not do.


Solution

  • Tcl will not read from variables that are not set to a defined value, and will instead throw the error that you received. (At the implementation level, an unset variable corresponds to a NULL and consistently generates an error when you try to read it; it's possible to trap that error and deal with it, of course.) If you've not set a value — such as via the variable declaration — the variable strictly exists (i.e., it has storage space and metadata allocated) but doesn't have anything in it so you get an error when you read from it. You can use info exists _id inside the method to detect this case if you want; scripts are not supposed to be able to see the difference between the exists-but-valueless and doesn't-exist-at-all states by long-standing policy.

    Itcl uses Tcl's basic variable infrastructure. It alters how Tcl looks for variables when running inside methods (the variable resolution mechanism) but everything after that is purely standard Tcl behaviour. Variables without values cannot be read, and pretend to not exist at all. (Indeed, if it wasn't for Itcl doing some special tricks, the variable would entirely not exist as that's a more efficient use of memory resources.)