Tcl: Setting a private variable of an owned instance within a class
Suppose the following code declarations:
itcl::class ObjectA {
private variable m_ownedObject
private variable m_someVariable
construc开发者_开发问答tor {} \
{
set m_ownedObject [ObjectA #auto]
}
protected method SetSomeVariable {newVal} {
set m_someVariable $newVal
}
public method SomeMethod{} {
$m_ownedObject SetSomeVariable 5
}
}
This is the only way I know how to modify m_someVariable
from within SomeMethod
on m_ownedObject. In other languages (say C/C++/C#/Java to name a few), I'm pretty sure I could just say something like:
m_ownedObject.m_someVariable = 5
Is there a way to do something like this in tcl, or do I always need to create protected getters and setters? Hopefully this is reasonably clear.
You cannot directly do what you're asking for in itcl. However, this being Tcl, you can work around that, and directly set the member variable from anywhere. I use a helper routine called memv
which you pass an instance and a variable name, and it returns a "reference" to that variable.
This obviously bypasses the private/protected mechanisms that Itcl set up, so you're violating abstractions using them. It's your call whether you want to use it. I find it invaluable for debugging, but don't it in production code.
The example usage is:
set [memv m_ownedObject m_someVariable] 5
The code for memv
is:
proc memv {obj varname} {
# have to look up the variable, which might be in a base class
# so do 'info variable' to get that, and the full name is the 3rd element
# next two lines handle pulling apart an array
set aindex ""
regexp -- {^(.+)\((.+)\)$} $varname ignore varname aindex
set var [lindex [$obj info variable $varname] 2]
if {$aindex == ""} {
return [list @itcl $obj $var]
} else {
return [list @itcl $obj $var\($aindex\)]
}
}
Similarly, I have a helper routine named memv
which allows you to call any method (including private and protected methods). It's usage is similar
[memf m_ownedObject SetSomeVariable] 5
And it's code is:
proc memf {obj fcnname} {
set f [$obj info function $fcnname]
if {[llength $f] != 5} {
error "expected '$obj info function $fcnname' to return something like 'private proc ::namespace::name args {...}' but got: $f"
}
set fullname [lindex [$obj info function $fcnname] 2]
set namespace [namespace qualifiers $fullname]
set function [namespace tail $fullname]
return [itcl::code -namespace $namespace $obj $function]
}
$m_ownedObject configure -m_someVariable 5
If you're declaring a variable as private, means that can be only accessed from within the class. And that's also valid for C/C++/Java ... so I'm not sure what are you expecting.
Anyway Tcl is a dynamic language, so you can do something like that.
itcl::class tclass {
foreach v {time distance} {
method get$v {} [subst -nocommands { return [subst $$v] }]
method set$v nuval [subst -nocommands { set $v \$nuval } ]
protected variable $v "Var $v"
}
}
And it will create all the getters
and setters
that you need ;)
You can find more info here: http://wiki.tcl.tk/17667
精彩评论