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.