Version 8 of persistent itcl

Updated 2002-08-18 13:25:35

The page Persistent incr-Tcl objects got me thinking about persistence.

The code presented there requires too much user intervention, I want something which handles more of the details automatically.

Here's a function which constructs a script which, when evaluated in global scope, will do what I think I want.

  # serialize extracts all variables and their current values into a script
  # such that `eval [serialize obj]' will set obj to those values
  proc serialize {obj {new ""}} {
      set result ""
      if {$new == ""} {
          set new $obj
      }
      foreach var [$obj info variable] {
          foreach {type name} [$obj info variable $var -type -name] break
          if {([namespace tail $name] != "this") && ($type != "common")} {
              set fromname "@itcl $obj $name"
              set toname "@itcl $new $name"
              if {[catch {
                  append result "eval set [list \[list ${toname}\]] [list [list [set $fromname]]]\n"
              } err]} {
                  puts stderr "err: $err"
              }
          }
      }
      return $result
  }

Here's a small test:

  class test_persist {
      common com "com val"        ;# common vars are unchanged by serialize
      private variable priv "priv default"
      public variable pub "pub default"
      protected variable prot "prot default"
      public variable single single_value_should_not_be_braced

      # make all variables' values uppercase
      method change {} {
          foreach var {priv pub prot} {
              set $var [string toupper [set $var]]
          }
      }

      constructor {} {
          # change values from the default
          set priv {priv value $ [] # \n \{\}}
          set pub {pub value $ [] # \n \{\}}
          set prot {prot value $ [] # \n \{\}}
      }
  }

  class test_p1 {
      inherit test_persist
      public variable sub_pub sub_pub
      private variable sub_priv sub_priv

      method test {} {
          foreach var [$this info variable] {
              foreach {type name val} [$this info variable $var -type -name -value] break
              puts "$name = $val"
          }
      }

      constructor {} {
          # needs to be here
      }
  }

  test_p1 t
  puts "Vars: [t info variable]"
  set lower [serialize t]
  puts "DUMP: '$lower'"
  t change        ;# uppercase t
  puts "Will be uppercase:"
  t test
  eval $lower
  puts "Should be lowercase:"
  t test        ;# check change

  test_p1 t2
  t2 change
  puts "Will be uppercase:"
  t2 test
  set tolower [serialize t \$T]
  puts "DUMP2: '$tolower'"
  set T t2
  eval $tolower
  puts "Should be lowercase:"
  t2 test

CMcC


Persistence and Distribution

This approach raises some interesting possibilities for persistence:

  • Each class instance can be represented by a metakit row
  • Tequila could be adapted to attach instance variables (or whole objects) in addition to simple arrays (Necessary modification to achieve this goal would be moderate.)
  • checkpointing