Version 7 of Tao Data Encapsulation

Updated 2007-07-31 13:21:29 by LV

TAO 8.5 uses the "dict with" mechanism for data encapsulation. (Boring eh?) Each object has a global variable, and recursion is handled by a stack. If you were to peer inside of a compiled class:

   ::tao::class foo {
          variable bat bing
          method bar {} {
                return $bing
          }
    }

    set obj [::tao::new foo #auto]
    info body [::tao::class_nspace foo]::bar 
    ....start of body ...

    set this [::tao::opeek]
    set statevar [::tao::object_dict $
    dict with $statevar {
          return $bing
     }

     ...end of body...

TAO 7.x uses a novel techique to handle data encapsulation, a "scope" command that lets one carry data around in bundles and unpack it on demand.

Example:

  scope ::myobj add color variable
  scope ::myobj add type  static myobj
  scope ::myobj add anArray hash

   proc testSet newcolor { 
      scope load ::myobj
      set color $newcolor
   }
   proc testGet {} {
      scope load ::myobj
      return $color
  }
  # Will TRY to reprogram a static value
  # does not throw an error, but neither does it change
  # the state of the encapsulation
  proc testStaticSet ignoredVal { 
      scope load ::myobj
      set type $ignoredVal
   }
  proc testStaticGet {} { 
      scope load ::myobj
      set type $type
   }


   proc testArraySet {var val} { 
      scope load ::myobj
      set anArray($var) $val
   }
   proc testArrayGet {var} { 
      scope load ::myobj
      return [lindex [array get anArray $var] 1]
   }

  testSet green
  testGet
  > green
  testSet blue
  testGet
  > blue
  testArraySet height 20
  testArrayGet height
  > 20
  testStaticSet garbage
  # note that changes to "static" vars are not retained
  # this is actually correct
  testStaticGet 
  > myobj

Implementation

There are a few pseudocode callouts that are required. One is "object_array", which maps an object name to a global variable. The others are 'get' which returns a value if it exists, or {} otherwise, ladd which adds a value to a list only if it is not present, and ldelete which removes an element from a list.

    proc scope {cmnd handle {varname {}} {type variable} {value NULL}} {
        upvar #0 [object_array $handle] state
        switch $cmnd {
            load { uplevel 1 [set state(script)] }
            add - del {

                array set vartypes [get state(info)]
                foreach vtype [array names vartypes] { 
                    ldelete vartypes($vtype) $varname
                }
                if { $cmnd == "add" } {
                    ladd vartypes($type) $varname

                    if { $value != "NULL" } { 
                        set state($varname) $value
                    }
                }
                set state(info) [array get vartypes]
                scope rebuild $handle
            }
            rebuild {
                set statevar [object_array $handle]
                upvar #0 $statevar state

                array set meta [get state(info)]
                set script {}

                ###
                #  this is really only for backward compadibility
                #  with classes generated for itcl
                #  enlightened clients will just call objdata(varname)
                #  directly
                ###

                append script \n "\# LOAD ENCAPSULATED DATA"
                append script \n [list set statevar $statevar]
                set varlist {}
                lappend varlist  ${statevar} objdata
                set usedvarnames {}        
                set statics [get meta(static)]

                foreach {var} [get meta(hash)] {
                    if { [lsearch $usedvarnames $var] >= 0 } continue
                    ladd usedvarnames $var
                    lappend varlist ${statevar}.${var} $var
                }

                foreach {var} [get meta(variable)] {
                    if { [lsearch $usedvarnames $var] >= 0 } continue
                    ladd usedvarnames $var
                    lappend varlist ${statevar}($var) $var
                }
                foreach {globvar localvar} $varlist {
                    if { [lsearch $statics $localvar] < 0 } { 
                        append script \n [list catch [list upvar #0 $globvar $localvar]]
                    }
                }
                foreach {var} $statics {
                    append script \n [list set $var [get ${statevar}($var)]]
                }
                set state(script) $script
            }
        }
    }

Category Design Category Object Orientation