An explanation, primarily by MS, of when and how a proc is compiled to bytecodes. Why compile to bytecode is a separate question.
This reflects my present understanding of all this, AFAIK essentially correct - I am aware of a lot of simplifications here, which I hope result in more clarity and not confusion. In particular, there is no mention of Tcl_Obj.
I also do not address the behaviour of variables here.
In case of doubt, read the source, Luke ... and do correct me please!
What happens when you *define* a proc?
Not much, actually: the source is saved as text, a command is created in the corresponding namespace. (The text may still have syntax errors or whatever - see procs as data structures).
What happens when you *invoke* a proc?
What happens when a command B is invoked in the body of proc A
What happens when bytecodes are executed?
Example
# define B proc B x { if $x { this is an error } else { set a b } } # define A proc A x {B $x} # invoke A: this causes compilation of A, start running A, # then invoke B (which cause its compilation). Both are # compiled OK A 0 ;# returns b A 1 ;# runtime error: invalid command name "this" A 0 ;# returns b, all is still OK # define a proc "this" proc this args {return "OK now"} # invoke A; previous bytecodes of both A and B are used; # at the invocation of 'this', it is found, parsed, # compiled and run A 1 ;# "this" is now found, returns "OK now" # redefine B, now using a bcc'ed command. B's previous # bytecodes are discarded, B is saved as text, no error proc B x { if $x { # this is a compile-time error set a b c } else { set a b } } # invoke A: use existing compilation of A, start running A, # then invoke B which cause its compilation. The error is at # compile time due to the bcc'ed [set] (this is an open bug, # actually), even the "correct" case fails: A 0 ;# wrong # args: should be "set varName ?newValue?"
The global $tcl_traceCompile permits observation of the compiler's activity: 1 tells you when compilation takes place, 2 shows you the bytecodes too.
$tcl_traceExec permits observation of the execution engine: 1 tells you whenever a proc is invoked, 2 whenever a command is invoked, 3 shows the actual bytecodes being executed.
de: You must compile tcl with the -DTCL_COMPILE_DEBUG flag, to make this work.
Cmcc: Is there any good reason that this isn't enabled by default? Does it impose a significant overhead? I suppose it must.
strick: Indeed it does.
DKF: Compilation debugging is now (8.4) enable-able using a suitable flag to configure, at least on UNIX.
For Tcl 8.6, there is a one-line patch that will disable all byte compiling except for expressions and substitutions. In TclCompileScript in tclCompile.c, find this code:
if ((cmdPtr != NULL) && (cmdPtr->compileProc != NULL) && !(cmdPtr->nsPtr->flags&NS_SUPPRESS_COMPILATION) && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES) && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) { int code, savedNumCmds = envPtr->numCommands; unsigned savedCodeNext = envPtr->codeNext - envPtr->codeStart; int update = 0;
and change that condition to
if ( 0 && (cmdPtr != NULL)