- eval arg ?arg ...?
Here's the inside scoop: eval is an old, old command, that's been in Tcl from the beginning.What's really going on with eval is this, at the coding level: formally, eval is about evaluation of scripts (although note that, in modern Tcl, it's merely an abbreviation for "uplevel 0 ..."). This makes one think of code-data duality, such languages as Lisp and Forth, "self-modifying programs", and related esoterica. Occasionally, eval is used in this way, and it's very powerful and crucial to Tcl that this be possible. All the commands--bind, everything with -command, and so on--that receive scripts as arguments depend on this.However, most Tcl applications don't need eval directly in their own coding for this use at all. They're solving end-user problems, not diving into introspection. Still, eval is pervasive in Tcl coding for a slightly "dirty" reason: it's how we used to expand arguments. ({*} is the modern method of expanding arguments.)... [invoke Joe English posting [1], explain variadic parameters, style, ...] ...That's the background necessary to understand the ruminations that follow.
Use of the eval command is considered "evil", dangerous or bad style by some Tcl'ers (because it leads to double substitution), but there are situations where its feature of removing one layer of list structure (like with concat) comes in just right. If you compose widgets in Tk, first you create them, then you manage them (register at a geometry manager, e.g. pack). You either have to keep track of what widgets you created, and repeat that list in the pack command, or just say
[Document Donal's (controversial?) linsert trick for pure-list evaluation.] [This is probably the place to mention tclguy's discussion [2] of the truly correct way to build a list for evaluation.]
The arguments to [eval] are concatenated into a string to be interpreted, but this operation does not guarantee that the string will be a well-formed script (i.e., one conforming to the Tcl parsing rules as laid out in the Tcl manual page).The following script breaks because the concatenation keeps the newlines from the list's string representation, making [eval] interpret the second element as a new command:
In some cases [eval] does work on lists - and its special. In particular, if eval is passed a pure list then it gets evaluated directly, without another round of substitution. However, I think the utility is just short of what it could be.When you pass eval a pure list, you can only execute a single command. What if we were to pass eval a list of pure lists - it should directly evaluate each of them, and return the value of the the last one evaluated. This sounds a lot like progn in lisp, and it seems like it would allow for some nifty bits of introspection - for example, if info body returned a pure list-of-lists rather than a string, that could be evaluated directly. Or modified. The whole program becomes a list of lists.The problem is how to signal to eval (or uplevel, namespace, bind, ...) that it is a list of lists rather than just a list. Could eval determine if its input is a pure list and the first argument of that is a pure list, then evaluate as progn?Another place this seems like it could be useful: I have a pkgIndex file with the line
RS 2004-02-06 - As usual in Tcl, functionality you miss you can easy roll yourself. I needed a progn-like list eval in RPN again, and did it similar to this:
[Explain discussion of {*} for argument-interpolation, ...]For example, if previously I coded this:
LV I just had to copy this over to the wiki - it is so neat!From comp.lang.tcl, Bob Techentin writes in response to a poster:It sounds like you're looking for something similar to /bin/sh "set -v" command which prints shell input lines as they are read, and "set -x" which prints expanded commands. Kind of like a verbose mode.Nope. Nothing like that. But you wouldn't have to write your own shell. You could walk through a script (a list of lines), and use info complete to decide how many lines are required to complete the command, then print both the command and the command's results. This seems to work.
[wtracy], 2008-06-23: I want the commands I run in eval to have their own set of variables independently of the calling script. Is there some way I can hand eval a context (maybe as an associative array?).Lars H: Sounds like you want a lambda (or possibly a closure, which is more difficult). If you're using Tcl 8.5, then have a look at apply.RS Long before 8.5, you could always write a little proc to hide its local variables (x in this example):
Use of the eval command is considered "evil", dangerous or bad style by some Tcl'ers (because it leads to double substitution), but there are situations where its feature of removing one layer of list structure (like with concat) comes in just right. If you compose widgets in Tk, first you create them, then you manage them (register at a geometry manager, e.g. pack). You either have to keep track of what widgets you created, and repeat that list in the pack command, or just say
eval pack [winfo children .]eval is often used with exec, to flatten input lists:
eval exec grep foo $filelistbecause otherwise grep would receive filelist as one long filename with embedded blanks. Or, if you want to append one list's elements to another:
set thislist [concat $thislist $thatlist] ;# can also be done as eval lappend thislist $thatlistAnother application is in building up a command in pieces (by appending to a string) and finally calling
eval $cmd
[Document Donal's (controversial?) linsert trick for pure-list evaluation.] [This is probably the place to mention tclguy's discussion [2] of the truly correct way to build a list for evaluation.]
The arguments to [eval] are concatenated into a string to be interpreted, but this operation does not guarantee that the string will be a well-formed script (i.e., one conforming to the Tcl parsing rules as laid out in the Tcl manual page).The following script breaks because the concatenation keeps the newlines from the list's string representation, making [eval] interpret the second element as a new command:
% set arg {a
b
c
}
a
b
c
% eval list $arg
ambiguous command name "b": bgerror binary breakTo solve this, construct the argument using list primitives like lappend, list, etc. DKF says: "list and eval are truly made for each other."Another solution is to use the following idiom:% eval [linsert $arg 0 list] a b clinsert converts its list argument to a well-formed list with single spaces separating elements, and then inserts further elements into it (if any of these elements contain newlines, they remain in the resulting string).It's important to remember that [eval] works on strings, not lists, and the rules for interpreting a string as a list are different than the rules for interpreting a string as a script.
In some cases [eval] does work on lists - and its special. In particular, if eval is passed a pure list then it gets evaluated directly, without another round of substitution. However, I think the utility is just short of what it could be.When you pass eval a pure list, you can only execute a single command. What if we were to pass eval a list of pure lists - it should directly evaluate each of them, and return the value of the the last one evaluated. This sounds a lot like progn in lisp, and it seems like it would allow for some nifty bits of introspection - for example, if info body returned a pure list-of-lists rather than a string, that could be evaluated directly. Or modified. The whole program becomes a list of lists.The problem is how to signal to eval (or uplevel, namespace, bind, ...) that it is a list of lists rather than just a list. Could eval determine if its input is a pure list and the first argument of that is a pure list, then evaluate as progn?Another place this seems like it could be useful: I have a pkgIndex file with the line
package ifneeded tls 1.4 "[list load [file join $dir libtls1.4.so]];[list source [file join $dir tls.tcl]]"where most of the lines are like
package ifneeded tclperl 2.3 [list load [file join $dir tclperl.so]]since they only need one command; but the tls line needs two commands. So why can't it be
package ifneeded tls 1.4 [list [list load [file join $dir libtls1.4.so]] [list source [file join $dir tls.tcl]]]
RS 2004-02-06 - As usual in Tcl, functionality you miss you can easy roll yourself. I needed a progn-like list eval in RPN again, and did it similar to this:
proc leval args {
foreach arg $args {
set res [uplevel 1 $arg]
}
set res ;# return last ("n-th") result, as Tcl evaluation does
}[Explain discussion of {*} for argument-interpolation, ...]For example, if previously I coded this:
set f [glob -nocomplain *.tcl] # some kind of code that ensures that $f has something in it eval exec lp $fwhat would I code now?
exec lp {*}$fLV I just had to copy this over to the wiki - it is so neat!From comp.lang.tcl, Bob Techentin writes in response to a poster:It sounds like you're looking for something similar to /bin/sh "set -v" command which prints shell input lines as they are read, and "set -x" which prints expanded commands. Kind of like a verbose mode.Nope. Nothing like that. But you wouldn't have to write your own shell. You could walk through a script (a list of lines), and use info complete to decide how many lines are required to complete the command, then print both the command and the command's results. This seems to work.
proc verbose_eval {script} {
set cmd ""
foreach line [split $script \n] {
if {$line eq ""} {continue}
append cmd $line\n
if { [info complete $cmd] } {
puts -nonewline $cmd
puts -nonewline [uplevel 1 $cmd]
set cmd ""
}
}
}
set script {
puts hello
expr 2.2*3
}
verbose_eval $scriptLV This proc is so slick! I love it!Lars H: Another approach to this (which also can see individual commands in if branches, loop bodies, etc.) is to use traces. Do we have that written down anywhere?[wtracy], 2008-06-23: I want the commands I run in eval to have their own set of variables independently of the calling script. Is there some way I can hand eval a context (maybe as an associative array?).Lars H: Sounds like you want a lambda (or possibly a closure, which is more difficult). If you're using Tcl 8.5, then have a look at apply.RS Long before 8.5, you could always write a little proc to hide its local variables (x in this example):
% eval {proc "" x {expr $x*$x}; "" 5}
25[wtracy]: Thanks. It looks like apply is the closest Tcl feature to what I want.[wtracy]: Actually, it looks like what I *really* want is to nest an eval command inside of a namespace eval block.[wtracy]: Okay, for the sake of any lost soul that comes along after me, this is what I really wanted to do all along: > set cmd {puts FOO}
puts FOO
> namespace eval MyNameSpace $cmd
FOONEM As mentioned, apply is probably a better choice in this case as it is less surprising wrt. variables. See dangers of creative writing for some related discussion. The apply version is: apply {{} { puts FOO } ::MyNameSpace}This has the benefit of evaluating the code within a fresh procedure context, meaning all variables are local to that context by default. See also namespace inscope/namespace code and you may also like dict with.eval versus bytecode edit
AMG: It appears [eval]'ed code does not get bytecode-compiled, even when [eval] is passed a single brace-quoted argument. The same is true for [uplevel 0] and [time]. [catch] and [if {1}] seem to be bytecoded. {*} also gets bytecoded, but it doesn't accept a script "argument", rather a single command line pre-chewed into an objv list. Bytecoding cannot take place when the argument is the product of [list], since the script isn't in a permanent Tcl_Obj.proc a {} {eval {for {set i 0} {$i < 100000} {incr i} {}}}
proc b {} {uplevel 0 {for {set i 0} {$i < 100000} {incr i} {}}}
proc c {} {time {for {set i 0} {$i < 100000} {incr i} {}}}
proc d {} {catch {for {set i 0} {$i < 100000} {incr i} {}}}
proc e {} {if {1} {for {set i 0} {$i < 100000} {incr i} {}}}
proc f {} { {*}{for {set i 0} {$i < 100000} {incr i} {}}}
proc g {} {eval [list for {set i 0} {$i < 100000} {incr i} {}]}
proc h {} {uplevel 0 [list for {set i 0} {$i < 100000} {incr i} {}]}
proc i {} {time [list for {set i 0} {$i < 100000} {incr i} {}]}
proc j {} {catch [list for {set i 0} {$i < 100000} {incr i} {}]}
proc k {} {if {1} [list for {set i 0} {$i < 100000} {incr i} {}]}
proc l {} { {*}[list for {set i 0} {$i < 100000} {incr i} {}]}
proc m {} {try {for {set i 0} {$i < 100000} {incr i} {}}}
a;b;c;d;e;f;g;h;i;j;k;l;m
time a 10 ;# 80723.8 microseconds per iteration - slow
time b 10 ;# 65380.2 microseconds per iteration - slow
time c 10 ;# 66024.8 microseconds per iteration - slow
time d 100 ;# 18888.3 microseconds per iteration - fast
time e 100 ;# 18779.3 microseconds per iteration - fast
time f 100 ;# 19375.2 microseconds per iteration - fast
time g 10 ;# 319111.5 microseconds per iteration - very slow
time h 10 ;# 342878.4 microseconds per iteration - very slow
time i 10 ;# 322279.2 microseconds per iteration - very slow
time j 10 ;# 316939.0 microseconds per iteration - very slow
time k 10 ;# 321865.5 microseconds per iteration - very slow
time l 10 ;# 344009.5 microseconds per iteration - very slow
time m 100 ;# 19503.0 microseconds per iteration - fastI want single-argument [eval] functionality in my code, but I also want bytecoding. [catch] has the undesirable side effect of hiding errors, so I guess I have to use [if {1}] which is a really weird idiom. Does anyone have any better ideas?AMG: I reran the tests and got better numbers. The current version of Tcl must be faster than whatever I used when I first did this benchmark (I'm using the same computer). Look in the page history to see the comparison. More importantly, I think I found a bytecoded [eval]: single-argument [try]. I added a test for it, and it turns out to be just as fast as the other "fast" methods. It's considerably less weird than [if {1}], and it doesn't hide errors.DKF: We've been focusing a bit more on improving the most cripplingly-slow cases, but three execution modes still exist that have fundamentally different speeds. There's compilation to bytecode-with-local-var-table (which is the fastest; the speed comes from being able to compile in indexes into the LVT into the generated bytecode, which this test is particularly sensitive to), there's compilation to bytecode-without-LVT (slower; variables have to be looked up each time they're accessed), and there's interpreting (slowest by far). There's not much point in doing a lot of comparison between the three; they all exist for a reason. (We could make straight eval/uplevel 0 of constant arguments work at full speed, but we see no reason to bother given how rare they are in real code, and it's better that time is kept simple anyway.) You can usually tell what sort of class of speed you're going to get by using tcl::unsupported::disassemble to look at the bytecode to see whether variables are accessed by index or by name, or whether everything's done by just building arguments and invoking “normal” commands.