Itcl cget code

This page provides a short discussion and an implementation on Itcl cget code, a piece of code that is run when an object property is retrieved.

Some languages, have a feature called public properties. One of them is C#. Virtually this means, that two blocks of code can be assigned with the public variables of a class. In C# this looks like in this example:

class A {
private string _name

public string Name {
get {
//...
return _name;
}
set {
_name = value;
//...
}
}
}

This is especially useful, if additional things should happen to the object when a property’s value is changed or retrieved from outside.
Itcl (http://incrtcl.sourceforge.net/) has had a similar concept since its beginning, but only for the change of an objects public variable. It was always possible to define a block of (I)tcl code to be run when the variable is configure‘d. So, an Itcl class could always have looked like this:

itcl::class A {
private variable _priv
protected variable prot

public variable value 0 {
set _priv [expr 2 * $value]
}

constructor {args} {
# ...
eval configure $args
}
}

If an object is constructed from this class, public variables can be given together with their values to the constructor. The eval configure $args manages to assign the values, where args consists of -variable value pairs – other arguments have to be processed first and removed from the list.
To retrieve the value later, the cget command can be used:

A aobj -value 4
# value is 4, _priv is 8 in the new object
aobj cget -value
# returns 4
aobj configure -value 8
# value is 8, _priv is 16 now
aobj cget -value
# returns 8

But what if the variable should reflect a certain object state, at the time cget is invoked? Consider for example, the value is to be multiplied by itself and this result is to be returned on cget – but the internal value of the variable should not be set to its power of 2. This is a simple construct, however there are more complicated constructs possible. It would be handy to have also a piece of code assigned to the variable that is executed, whenever cget is invoked.

I have implemented this feature for Itcl – among others, but more on that later. The sources are part of Tclkick, which itself can be checked out from sourceforge. Check out this page for more info on Tclkick

The enhanced Itcl understands itcl::class definitions like the following:

itcl::class A {
private variable _priv
protected variable prot

public variable value 0 {
set _priv [expr 2 * $value]
} {
# do whatever cget code you want
return $value ;# or [expr $value * $value] or...
}

constructor {args} {
# ...
eval configure $args
}
}

Furthermore, a new command is added to the itcl namespace: “itcl::cgetbody”. This command enables redefinition of cget code, much like “itcl::configbody” does for configuration code. So it is possible to define:

itcl::configbody ::A::value {
set _priv [expr 2 * $value]
}

itcl::cgetbody ::A::value {
# do what you like
return [expr 2 + $value * $value]
}

Besides fixing some compilation warnings, the patch does nothing else to Itcl. The full functionality of the “old style” Itcl is kept and all Itcl code made previously will run with the patched Itcl as well – I don’t guarantee for that, since the patch comes with absolutely no warranty like Itcl itself. However, I have valid reasons to claim that everything will work with the patch – I for myself have some 10k production Itcl code running and this goes fine up to now.
The only thing you might need to do is recompiling any C extensions that use the Itcl stubs library. I needed to provide a new interal declaration Itcl_CgetBodyCmd and to rerun genstubs.tcl. So, mystic errors could appear while using not-recompiled extensions. This holds especially true for Itk. I’ve experienced errors there until I recompiled and relinked Itcl against the new libitclstub33.a.
The whole patch/make/install procedure can be done on windows/mingw too. The resulting dll can be copied into an ActiveTcl’s lib/itcl3.3 subdirectory, thanks to the stubs mechanism.

The patch provides a further functionality: config and cget code for protected variables. This makes sense in a way, because like public variables and their code is abstracted from the outside of the object, protected variables and their code should be abstracted by a base class from its derived classes. So, if you create a base class and derive another from it, it is possible now to configure/cget the value of a protected variable (and run it’s config/cget code) but only from within object methods of the derived class. The latter is important: protected variables can not be configured/cget from outside, they will not be found. It is also not possible to give a -protected_variable value pair as argument to a method that expects a varargs list, like in this example:

class A {
protected variable prot "" {
# config code
} {
# cget code
}

constructor {args} {
# ...
eval configure $args
}
}

# ....
A aobj -prot 23

This will raise an error – protected variables are not to be configured from outside at all. But giving a protected variable to a non-varargs list will not raise an error, because of two reasons: First, Itcl assumes you know what you do. Second, non-varargs lists are rarely used to “eval configure”.

Have fun ;-)

Comments Off