Posted to tcl by aspect at Mon Jul 27 00:38:35 GMT 2015view raw
- #
- # I'm not sure how useful this is yet, but it's a little hack for reloadable classes with persistent objects
- # Inspiration from sdw's "Lifecycle of Objects" presentation
- #
- # It relies on some TclOO magic sauce:
- #
- #  * the class of an object can be changed during its lifetime without affecting the rest of the object's state
- #  * when a class is destroyed, its own destructor is run before its instances are destroyed
- #  * subclassing oo::class to make a metaclass is trivial (if a little mind-bending)
- #
- # Once these are established, all that remains is how to keep track of the zombies' original class for later
- # resuscitation.  It's tempting to try and store this in the zombie class, but a regular namespace variable
- # proves simpler.
- #
- #pkg -export {lazarus} zombies
- namespace eval zombies {
-  
-     oo::class create zombie {
-         method unknown {cmd args} {
-             puts "Unknown method call on zombie! [self] [list $cmd] $args"
-             throw [list TCL LOOKUP METHOD $cmd] "Zombie methods cannot be called!"
-         }
-     }
-  
-     variable Horde  ;# where zombies are arranged by (former) class
-  
-     proc infect {cls} {
-         variable Horde
-         foreach obj [info class instances $cls] {
-             puts "Burying $cls $obj"
-             oo::objdefine $obj class zombie
-             dict lappend Horde $cls $obj
-         }
-     }
-  
-     proc come_forth {cls} {
-         variable Horde
-         if {[info exists Horde] && [dict exists $Horde $cls]} {
-             foreach obj [dict get $Horde $cls] {
-                 puts "Waking zombie $cls $obj"
-                 oo::objdefine $obj class $cls
-             }
-             dict unset Horde $cls
-         }
-     }
-  
-     oo::class create lazarus {
-         superclass oo::class                ;# Lazarus is a metaclass
-         constructor args {
-             next {*}$args                   ;# create the class normally
-             ::zombies::come_forth [self object]   ;# raise the dead!
-         }
-         destructor {
-             ::zombies::infect [self]
-         }
-     }
-  
-     namespace export lazarus
- };  namespace import zombies::*
-  
-  
- proc mkclass {} {
-     lazarus create C {
-         variable V
-         constructor {v} {set V $v}
-         method v {args} {set V {*}$args}
-     }
- }
-  
- mkclass
- C create a "Hello"
- C create b "World"
- puts "[a v] [b v]; [a v] [b v Tcl!]"
- try {a v} on error {e o} {puts "ERROR: $e"}
- C destroy
- mkclass
- puts "[a v] [b v]"
-