save the whole runtime environment to a file and restore it later

Shin The Gin - Wouldn't it be nice for an interative environment to save its complete state into a file and restore it later?

How would one do it with Tcl?

I know Tcl has a lot of introspection capabilities, but do they enable a complete saving of states?

RS: See serializing and Dumping interpreter state

NEM: See also continuation, depending on what is meant by interpreter state.

escargo: It sounds like saving and restoring a Smalltalk workspace (or also going back a ways, an APL workspace). Squeak Smalltalk [L1 ] has workspaces.

Shin The Gin escargo: Yes, that's what I had in mind. I think of it as a multistep routine.

  1. Save all variables
  2. Save all arrays
  3. Save all procedures
  4. Save all images
  5. Traverse and save the widget tree

Whereas save here means to write out tcl code, that can be sourced later. In a bigger picture, I dream of a TclTk environment that comes up with a Transcript like Smalltalk, workspaces with "Do It" and "Print It" in their option menu and some Tools for browsing lists, arrays and text. I wouldn't need a Class Hierarchy Browser, but instead there should be a Namespace Browser and a nice File Browser.

I've done some investigations last night and made envsave.tcl. It's not as complete as the list above, but saves alls globals, procedure and widgets.

escargo - Have you looked at XotclIDE? It's almost like the Smalltalk browser, and might have some similarities to Squeak Smalltalk. I believe it has a Transcript window.

Shin The Gin escargo Been there, done that! I'm not primarily after Transcript windows, but I like the idea of a TclTk environment that is fully respresentable in Tcl code. Could Tcl ever be written in Tcl? I know about Forth inpterpreters being written in Forth, Basic interpreters written in Basic etc. - I like the XotclIDE much and already had nice results with it, but it doesn't follow the concept of Image based computing like Smalltalk does. Instead, it features a database driven code repository.

George Peter Staplin You should be able to do essentially what Emacs does, and dump the dynamic portions of the executable image. Basically with an ELF executable you can dump the .data segment to an image file, and then restore it on the next startup. There's a little more involved, but it's definitely possible.

Lars H: This "Emacs approach" is rather crude though, GPS. Languages with poor introspection capabilities have to do it by dumping raw memory (MS Word also comes to mind), but surely Tcl can do better! (OK, sometimes speed is of the essence, but usually it's not.)

RJ I do this.. only saves variable contents. To save window state, capture widget contents to variables first, then in the restore, insert them. Same with focus, tags, etc. (Global only here. For namespaces, just add another nested level of foreach [lappend [namespace children ::] ::])

 proc save_state        {}        {
   uplevel        {
                set fh [open $statefile w]
                foreach v [info var]        {
                        if [array exists $v]        {
                                puts $fh "a $v = [array get $v]" 
                        } else {
                                puts $fh "v $v = [set $v]"
                        }
                }
                close $fh
   }
 }

 package require fileutil  
 # cuz I love this package (obv. you could open/close a file yourself)
 proc restore_state {}        {
   uplevel {
                fileutil::foreachLine l $::statefile        {
                        if {[lindex $l 1] == "type"}        {
                                continue
                        }
                        if {[lindex $l 0] == "a"}        {
                                array set [lindex $l 1] [lrange $l 3 end]
                        #        puts "setting a [lindex $l 1]"
                        } else {
                                set [lindex $l 1] [lrange $l 3 end]        
                        #        puts "setting v [lindex $l 1]"
                        }
                }
                puts "Done restoring session"
   }
 }

Same stuff, but I like this better:

 # save vars and arrays
 proc save_state {} {
    uplevel 1 {
        set fh [open $::statefile w]
        foreach v [info vars] {
            if [array exists $v] {
                puts $fh [list array set $v [array get $v]]
            } else {
                puts $fh [list set $v [set $v]]
            }
        }
        close $fh
    }
 }

 # restore
 proc restore_state {} {
    uplevel 1 {
        source $::statefile
    }
 }

LV 2009-Sep-16 There's a gotcha here that needs to be recognized. Dumping variables and then in a new process reading them back in might work, but depending on what the variable represents, the restore of the variable may not be useful.

Take, for instance, this code:

set fd [open "/etc/passwd" "r"]
set line [read $fd]

If one blindly runs the save state type procedure, what one ends up is an fd that has a string value that is the equivalent of this script - however, the internal state of the file handle is not replicated, so any attempt (after restoring the saved state in a new process) to make use of $fd to read the next line of the password file will fail. Not only that, but the state of the password file itself may very well have changed so that even if one were able to dump the internal data structures and then attempted to reopen the file and position to the byte offset originally pointed to, the next read would not necessary represent a valid record.

The idea of checkpoint/restart is a tough nut to crack. One has to carefully detail the contract for the save/restore so that the user doesn't think they are getting more than they actually are.


See also: