:TITLE: Child interpreters
;#
;# RCSID: $Header: /home/clif/CVS_ROOT/TclTutor/Tcl43.lsn,v 1.2 2000/04/24 16:17:53 clif Exp $
;# Copyright (c) 1995 Clif Flynt
;# 9300 Fleming Rd.
;# Dexter, MI  48130
;# clif@cflynt.com
;# See file "NOTICE" for licensing terms.
;#
:LESSON_TEXT_START_LEVEL 0:
The <B>interp</B> command creates new child interpreters within an
existing interpreter.  The child interpreters can have their own sets of
variables and files, or they can be given access to items in the 
parent interpreter.
<P>
If the child is created with the <B>-safe</B> 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)
site.
<P>
The names of child interpreters are a hierarchical list.  If interpreter 
<B>foo</B> is a child of interpreter <B>bar</B>, then it can be 
accessed from the toplevel interpreter as <CODE>{bar foo}</CODE>.
<P>
The primary interpreter (what you get when you type tclsh) is the
empty list {}.
<P>
The <B>interp</B> command has several subcommands and options.  A
critical subset is:

<DL>
<B><DT>interp</B> create <I>?-safe? ?name?</I>
<DD>Creates a new interpreter and returns the name.  If the 
<I>-safe</I> option is used, the new interpreter will be unable to
access certain dangerous system facilities.
<B><DT>interp</B> delete <I>name</I>
<DD> Deletes the named child interpreter.
<B><DT>interp</B> eval <I>args</I>
<DD> This is similar to the regular <B>eval</B> command, except that
it evaluates the script in the child interpreter instead of the
primary interpreter.  The <B>interp eval</B> command  concatenates
the args into a string, and ships that line to the child interpreter
to evaluate.
<B><DT>interp</B> alias <I>srcPath srcCmd targetPath targetCmd ?arg arg?</I>
<DD> The <B>interp alias</B> command allows a script to share 
procedures between child interpreters or between a child and the primary 
interpreter.
</DL>
<P>
Note that slave interpreters have a separate state and namespace, but
do <B>not</B> have separate event loops.  These are not threads, and they
will not execute independantly.  If one slave interpreter gets stopped
by a blocking I/O request, for instance, no other interpreters will be
prcessed until it has unblocked.  
:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
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.
<P>
The <B>interp</B> command creates new child interpreters within an
existing interpreter.  The child interpreters can have their own sets of
variables and files, or they can be given access to items in the 
parent interpreter.
<P>
If the child is created with the <B>-safe</B> 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)
site.
<P>
The names of child interpreters are a hierarchical list.  If interpreter 
<B>foo</B> is a child of interpreter <B>bar</B>, then it can be 
accessed from the toplevel interpreter as <CODE>{bar foo}</CODE>.
<P>
The primary interpreter (what you get when you type tclsh) is the
empty list {}.
<P>
The <B>interp</B> command has several subcommands and options.  A
critical subset is:

<DL>
<B><DT>interp</B> create <I>?-safe? ?name?</I>
<DD>Creates a new interpreter and returns the name.  If the 
<I>-safe</I> option is used, the new interpreter will be unable to
access certain dangerous system facilities.
<B><DT>interp</B> delete <I>name</I>
<DD> Deletes the named child interpreter.
<B><DT>interp</B> eval <I>args</I>
<DD> This is similar to the regular <B>eval</B> command, except that
it evaluates the script in the child interpreter instead of the
primary interpreter.  The <B>interp eval</B> command  concatenates
the args into a string, and ships that line to the child interpreter
to evaluate.
<B><DT>interp</B> alias <I>srcPath srcCmd targetPath targetCmd ?arg arg?</I>
<DD> The <B>interp alias</B> command allows a script to share 
procedures between child interpreters or between a child and the primary 
interpreter.
</DL>
<P>
Note that slave interpreters have a separate state and namespace, but
do <B>not</B> have separate event loops.  These are not threads, and they
will not execute independantly.  If one slave interpreter gets stopped
by a blocking I/O request, for instance, no other interpreters will be
prcessed until it has unblocked.  
<P>
The example below shows two child interpreters being created under
the primary interpreter {}.  Each of these interpreters is given a variable
<CODE>name</CODE> which contains the name of the interpreter.
<P>
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 <CODE> interp eval</CODE> a <CODE>proc</CODE>
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 <CODE> interp alias</CODE> command.
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
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.
<P>
The <B>interp</B> command creates new child interpreters within an
existing interpreter.  The child interpreters can have their own sets of
variables and files, or they can be given access to items in the 
parent interpreter.
<P>
If the child is created with the <B>-safe</B> 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)
site.
<P>
The <B>-safe</B> option allows you to build client/server based systems
in which a Client sends Tcl commands to the Server, and the server can
evaluate these commands in a safe interpreter to ensure that rogue clients
do not damage the Server.  This gives you a great deal of power, since you
don't need to define any new syntax for the client/server communication,
or write any special parsing code.
<P>
The names of child interpreters are a hierarchical list.  If interpreter 
<B>foo</B> is a child of interpreter <B>bar</B>, then it can be 
accessed from the toplevel interpreter as <CODE>{bar foo}</CODE>.
<P>
The primary interpreter (what you get when you type tclsh) is the
empty list {}.
<P>
The <B>interp</B> command has several subcommands and options.  A
critical subset is:

<DL>
<B><DT>interp</B> create <I>?-safe? ?name?</I>
<DD>Creates a new interpreter and returns the name.  If the 
<I>-safe</I> option is used, the new interpreter will be unable to
access certain dangerous system facilities.
<B><DT>interp</B> delete <I>name</I>
<DD> Deletes the named child interpreter.
<B><DT>interp</B> eval <I>args</I>
<DD> This is similar to the regular <B>eval</B> command, except that
it evaluates the script in the child interpreter instead of the
primary interpreter.  The <B>interp eval</B> command  concatenates
the args into a string, and ships that line to the child interpreter
to evaluate.
<B><DT>interp</B> alias <I>srcPath srcCmd targetPath targetCmd ?arg arg?</I>
<DD> The <B>interp alias</B> command allows a script to share 
procedures between child interpreters or between a child and the primary 
interpreter.
</DL>
<P>
Note that slave interpreters have a separate state and namespace, but
do <B>not</B> have separate event loops.  These are not threads, and they
will not execute independantly.  If one slave interpreter gets stopped
by a blocking I/O request, for instance, no other interpreters will be
prcessed until it has unblocked.  
<P>
The example below shows two child interpreters being created under
the primary interpreter {}.  Each of these interpreters is given a variable
<CODE>name</CODE> which contains the name of the interpreter using the
<CODE> interp eval $int [list set name $int]</CODE> command.
<P>
Note the uses of list, quotes and bracketed strings for the <CODE>
interp eval</CODE> commands.  The <CODE>interp eval</CODE> command
concatenates the arguments into a list, as the <CODE>eval</CODE> command
does.  If you try to <CODE> interp eval</CODE> a command like :
<P>
<CODE>interp eval $foo [list puts "the value of $bar in $foo is"]</CODE>
<P>
Both the <CODE>$foo</CODE> and <CODE>$bar</CODE> will be substituted in
the parent interpreter before the line is evaluated in the child interpreter.
<P>
If you escape the <CODE>$bar</CODE> to substitute <CODE>$foo</CODE> in the parent
and <CODE>$bar</CODE> in the child like this:
<P>
<CODE>interp eval $foo [list puts "the value of bar in $foo is \$bar"]</CODE>
<P>
You'll find that the output resembles :
<P>
<CODE> the value of bar in interp2 is $bar</CODE>
<P>
Using the <CODE>list</CODE> to group the arguments to <CODE>interp eval</CODE>
made the command passed to the child interpreter resemble this:
<P>
puts {the value of bar in interp2 is $bar}
<P>
Because lists are grouped with braces.  Since the argument to <CODE>puts</CODE>
in the child interpreter is grouped with braces, no substitution occurs.
<P>
If you want substitution to occur within the child interpreter, you may 
need to create the command using braces, or using the format or concat
commands as shown in lessons 32, 33 and 34.
<P>
The last line in the example is an error.
The <CODE>interp alias</CODE> 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 <CODE> interp eval</CODE> a <CODE>proc</CODE>
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 <CODE> interp alias</CODE> command.
:TEXT_END:

:CODE_START:
set i1 [interp create firstChild]
set i2 [interp create secondChild]

puts "first child interp:  $i1"
puts "second child interp: $i2\n"

# Set a variable "name" in each child interp, and
#  create a procedure withint each interp 
#  to return that value

foreach int [list $i1 $i2] {
  interp eval $int [list set name $int]
  interp eval $int {proc nameis {} {global name; return "nameis: $name";} }
}  

foreach int [list $i1 $i2] {
    interp eval $int "puts \"EVAL IN $int: name is \$name\""
    puts "Return from 'nameis' is: [interp eval $int nameis]"
}

#
# A short program to return the value of "name"
#
proc rtnName {} {
    global name
    return "rtnName is: $name"
}

#
# Alias that procedure to a proc in $i1

interp alias $i1 rtnName {} rtnName 

puts ""

# This is an error.  The alias causes the evaluation
#  to happen in the {} interpreter, where name is
#  not defined.

puts "firstChild reports [interp eval $i1 rtnName]"


:TEXT_END:
