When is a good time to use eval?

eval (itself properly seen as a specialization of uplevel) is a powerful Tcl command. Beginning programmers often regard it rather magically, though, and are susceptible to bad habits in its use. Let's straighten those out here:

First, dense eval-ing often is a symptom of misunderstanding [L1 ] [L2 ], generally of the "working too hard" [L3 ] variety. Also, eval has security implications [explain], so it's appropriate systematically to analyze each instance of an eval in any particular application, and explicitly review that they're all "material".


RS: eval is no big mystery, just the heart of Tcl :) Very similar to Lisp interpreters, an interactive tclsh has a read-eval-print loop that could be written, oversimplified, as

while 1 {
    puts -nonewline "% "
    flush stdout
    gets stdin command
    if {$command eq "exit"} break
    set res [eval $command]
    puts $res
}

In general, whenever you have a command in a string or list, or several lists, eval is the way to evaluate that. As eval removes one layer of word wrapping, one can use it well as long as 8.5's {*} isn't available:

eval pack [winfo children .] -fill x

But, CL emphasizes, most conventional Tcl-based application programming has few well-founded occasions to trade on the code-data duality, so, to first approximation, eval should only appear in these list-bursting or {*}-like instances.

Anything else is a candidate for review as a misunderstanding.


AMG, amplifying the above: I use [eval] when I wish I had {*} but don't, and when I'm letting the user interactively enter Tcl commands. I really can't think of any other times when it's called for.

Here's another case where I make use of [eval]-like functionality but through other means: programmatically-generated code. This is a wonderful thing made possible by Tcl. But rather than use [eval] (or [uplevel]) directly on the generated command or script, I'm more likely to give it to [proc] or [apply]. And if it's not a full script but rather just a command, I'll use {*} to execute it.

When I say "just" a command, I'm humorously and ironically trivializing things. A single command can contain the universe. [eval] itself is an example of such. :^)

If it's a full script but it's not appropriate for it to be in its own stack frame, single-argument [try] is a good alternative to [eval] which provides superior performance if the script argument is used repeatedly rather than regenerated each time.