开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜