Version 0 of Tao Data Encapsulation

Updated 2007-06-08 16:32:22 by seanw

TAO 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 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]
   }
   proc testGet {} {
      scope load ::myobj
      return $color
  }
  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
            }
        }
    }