For most applications, a single interpreter and subroutines are quite sufficient. However, if you are building a client-server system (for example) you may need to have several interpreters talking to different clients, and maintaining their state. You can do this with state variables, naming conventions, or swapping state to and from disk, but that gets messy.
The
interp
command creates new child interpreters within an existing interpreter. The child interpreters can have their own sets of variables, commands and open files, or they can be given access to items in the parent interpreter.
If the child is created with the
-safe
option, it will not be able to access the file system, or otherwise damage your system. This feature allows a script to evaluate code from an unknown (and untrusted) source.
The names of child interpreters are a hierarchical list. If interpreter
foo
is a child of interpreter bar
, then it can be accessed from the toplevel interpreter as {bar foo}
.
The primary interpreter (what you get when you type tclsh) is the empty list
{}
.
The
interp
command has several subcommands and options. A critical subset is:interp create
-safe
name
- Creates a new interpreter and returns the name. If the
-safe
option is used, the new interpreter will be unable to access certain dangerous system facilities. interp delete
name
- Deletes the named child interpreter.
interp eval
args
- This is similar to the regular
eval
command, except that it evaluates the script in the child interpreter instead of the primary interpreter. Theinterp eval
command concatenates the args into a string, and ships that line to the child interpreter to evaluate. interp alias
srcPath srcCmd targetPath targetCmd
arg arg
- The
interp alias
command allows a script to share procedures between child interpreters or between a child and the primary interpreter.
Note that slave interpreters have a separate state and namespace, but do not have separate event loops. These are not threads, and they will not execute independently. If one slave interpreter gets stopped by a blocking I/O request, for instance, no other interpreters will be processed until it has unblocked.
The example below shows two child interpreters being created under the primary interpreter
{}
. Each of these interpreters is given a variable name
which contains the name of the interpreter.
Note that the alias command causes the procedure to be evaluated in the interpreter in which the procedure was defined, not the interpreter in which it was evaluated. If you need a procedure to exist within an interpreter, you must
interp eval
a proc
command within that interpreter. If you want an interpreter to be able to call back to the primary interpreter (or other interpreter) you can use the interp alias
command.Example
set i1 [interp create firstChild]set i2 [interp create secondChild]puts "first child interp: $i1"# Set a variable "name" in eachputs "second child interp: $i2\n " child interp, and # create a procedure within each interpp eval $int [list set n# to return that value foreach int [list $i1 $i2] { inte rame $int]eval $int {proc nameis {} {global name; return "nameis: $name";} } } foreainterp ch int [list $i1 $i2] { interp eval $int "puts \"EVAL IN $int: name is \$name\""o return the value of "name" # proc rtnName {} { global nputs "Return from 'nameis' is: [interp eval $int nameis]" } # # A short program tame return "rtnName is: $name" } # # Alias that procedure to a proc in $i1 interp alias $i1 rtnName {} rtnName puts ""stChild reports [interp eval $i1 rtnName]"# This is an error. The alias causes the evaluation # to happen in the {} interpreter, where name is # not defined. puts "fir
No comments:
Post a Comment