A number of difficult questions have arisen, and continue to arise concerning the details about how Tcl commands are evaluated.
This page has been created to lay out the details of Tcl command evaluation in order to see the various points at which existing behavior might be modified, or new behavior might be attached.
I find it easiest to follow the details by working from the inside out.
Layer 0: Tcl_ObjCmdProc edit
The innermost core of any Tcl command is a
Tcl_ObjCmdProc, a C routine that matches the prototype:
typedef int (Tcl_ObjCmdProc) (
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj * const objv[]);
A new Tcl command gets created by writing a
Tcl_ObjCmdProc, associating it with a
ClientData, and with a command name in an
interp, via a call to
Tcl_CreateObjCommand.
The
Tcl_ObjCmdProc gets passed the associated
ClientData, the interp, and the full
Tcl_Obj array,
objv, of the words of the command being evaluated.
The
objv[1] ...
objv[objc-1] values are the arguments to the command, and can influence the result. The
Tcl_ObjCmdProc should avoid changing behavior based on the value of
objv[0] however, for a few reasons. First it is a property of Tcl commands that they can be [rename]d. Thus the value of
objv[0] may very well not be the command name originally passed to
Tcl_CreateObjCommand. Second, as part of command evaluation, the Tcl internals will have interpreted the
Tcl_Obj objv[0] as the
Tcl_ObjType cmdName. This means the internal rep of
objv[0] will be that of a
cmdName, and any other internal rep someone tried to pass will be lost.
Another particularly nasty example of the bugs that can arise depending on the value of
objv[0] is Tcl Bug 1016167. [
1]
Rather than
objv[0], any state information needed to influence the command operations beyond the values of the arguments should be kept in the
ClientData.
Note also the
const restriction on the
objv argument. You should not (and the compiler should not let you) write to any of the
objv[i] slots. The
Tcl_Obj's themselves might be modified (typically by
shimmering), but the pointers may not be overwritten.
One thing that the
objv[0] value can be used for is to construct syntax error messages. Often
Tcl_WrongNumArgs is used for this.
The
Tcl_ObjCmdProc can count on the result of the interp having been reset. It is expected to return a return code value (
TCL_OK,
TCL_ERROR, etc.). It may set the interp result, if the reset state is not correct. (
Tcl_SetObjResult, etc.) It may also set the errorInfo and/or errorCode values if it is returning TCL_ERROR. (
Tcl_AddErrorInfo,
Tcl_SetErrorCode, etc.)
Possible Enhancements
Might need a C API to set values in the return options dictionary. Currently this is possible at the script level using [return], but there's no C API currently for that. Such a routine would cover errorInfo and errorCode setting, but would also be more general.
As
GPS has recently pointed out, the absence of this C API is all that prevents an extension from being able to provide its own [proc] replacement. The inability to create [proc]-like commands using only the public C API is one reason that important, powerful extensions like Itcl and XOTcl require access to Tcl's internals.
Layer 1: command dispatch: Tcl_ObjCmdProc callers edit
There are several routines in Tcl that currently call Tcl_ObjCmdProc's to perform command dispatch:
TclEvalObjvInternal
TclInvokeObjectCommand
TclObjInvoke
Tcl_Import
InvokeImportedCmd
They are not fully consistent with one another in how they manage command dispatch.
Over the years, Tcl has grown a large set of duties for the command dispatcher code to attend to. It is supposed to manage interpreter traces set by
Tcl_CreateTrace and
Tcl_CreateObjTrace. It is supposed to manage command execution traces. It is supposed to manage interpreter limits. It is supposed to see the asynchronous code gets a chance to execute. And probably more...