- TCL_EVAL_INVOKE is only used for interp alias calls.
- TCL_EVAL_GLOBAL is used for source, history, package
HISTORYNote: revision numbers refer to the file tclBasic.c1.65 (starting point)
- TCL_EVAL_GLOBAL: resolves cmd and runs traces in caller's scope, runs cmd in #0
- TCL_EVAL_GLOBAL: no change
- TCL_EVAL_NO_TRACEBACK: same thing, just avoids producing an error message
- TCL_EVAL_GLOBAL: no change
- TCL_EVAL_INVOKE: resolves cmd in #0, runs unknown and traces in caller's, runs cmd in #0
- TCL_EVAL_GLOBAL: resolves cmd in #0, runs unknown and traces in caller's, runs cmd in #0 (same as TCL_EVAL_INVOKE)
- TCL_EVAL_INVOKE: no change
- TCL_EVAL_GLOBAL: everything at #0
- TCL_EVAL_INVOKE: no change
- TCL_EVAL_GLOBAL: no change
- TCL_EVAL_INVOKE: changed ns for lookup and unknown processing, restored to caller's for traces and command running. If the traces cause a renewed lookup, the second one proceeds in caller's scope (this is a previously undetected bug [4]).
COMMENTSI think that TCL_EVAL_GLOBAL has essentially converged to its proper meaning.In order to judge if this is the case for TCL_EVAL_INVOKE it is necessary to specify what that meaning is. The meaning is do whatever is needed for alias invocations, but that itself is not quite clear. It has at least two independent components:
- Do not produce an error message
- Control the lookup and execution environment to do the right thing
There are several difficulties with the idea of resolving the command name in one namespace, then executing it in the caller's context. Essentially that info level breaks in one or the other of its different usages:
- [uplevel 1 [info level 0]] is expected to call the current proc again. This breaks as the lookup will now be done in the caller's context, which is not guaranteed to be the same as the lookup context for the present call. One famous user of this idiom is every; others are self, wrapping commands, ...
- [lindex [info level 0]] is expected to return the current proc's name; if necessary, some [namespace tail] and some [namespace current] allows the FQ name of the proc to be determined, even if it was renamed or accessed via an import or alias. If [info level 0] is "corrected" to provide a list that reproduces the current call from the [uplevel 1] env, this usage is broken.
- [llength [info level 0]] is widely used (also in tcllib) to determine the actual number of arguments received, which is otherwise impossible to determine when some arguments have default values. If [info level 0] is "corrected" to provide a list that reproduces the current call from the [uplevel 1] env, this usage is broken when a curried command is used - [interp alias] with default arguments.
mig@ice:/tmp$ cat /tmp/test set res {} proc x {} { if {![llength $::res]} { set ::res [list [info level 0] :: [uplevel 1 [info level 0]]] } else { return :: } } namespace eval a { proc x {} {return ::a} } interp alias {} y {} x namespace eval a y puts $res mig@ice:/tmp$ /home/CVS/tcl8.3.4/unix/tclsh test x :: ::aTcl8.4 and 8.5 give the same result: in this configuration, [uplevel 1 [info level 0]] fails to produce a second call to the same function. This a bug in the idiom that is fairly difficult to hit: the alias' target has to be shadowed by a command in the caller's context for it to fail.Note that the situation is actually easily solvable for [interp alias]: it could just call the target with a FQ name, which would insure that it is looked up globally as specified. An TCL_EVAL_INVOKE would just be reduced to TCL_EVAL_NO_BACKTRACE again. The only change would be in stack traces.In 8.5 that solution may not be optimal, as it would disable the new namespace path/unknown features for these calls.Tip 283 would cause the bug in this idiom to be easier to hit as the real target command is generally not in the global namespace. A failure will occurs whenever the ensemble command is defined on a namespace other than ::, and it is called from any namespace other than its own.