Eric Boudaillier: For a bytecode experimentation, I decided to generate bytecode for the K operator, or, more precisely, the idiom [K $x [set x ""]]]. Here is the result, with the help of the anatomy of a bytecoded command and the set compile command TclCompileSetCmd().
int TclCompileClearCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the
CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; int isScalar, simpleVarName, localIndex, numWords; int code = TCL_OK; numWords = parsePtr->numWords; if (numWords != 2) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"clear varName\"", -1); return TCL_ERROR; } /*
*/ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar); if (code != TCL_OK) { goto done; } /*
*/ if (simpleVarName) { if (isScalar) { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, localIndex, envPtr); } else { TclEmitInstInt4( INST_LOAD_SCALAR4, localIndex, envPtr); } } else { TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr); } } else { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1( INST_LOAD_ARRAY1, localIndex, envPtr); } else { TclEmitInstInt4( INST_LOAD_ARRAY4, localIndex, envPtr); } } else { TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr); } } } else { TclEmitOpcode(INST_LOAD_STK, envPtr); } /*
*/ code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar); if (code != TCL_OK) { goto done; } TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); if (simpleVarName) { if (isScalar) { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1( INST_STORE_SCALAR1, localIndex, envPtr); } else { TclEmitInstInt4( INST_STORE_SCALAR4, localIndex, envPtr); } } else { TclEmitOpcode(INST_STORE_SCALAR_STK, envPtr); } } else { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1( INST_STORE_ARRAY1, localIndex, envPtr); } else { TclEmitInstInt4( INST_STORE_ARRAY4, localIndex, envPtr); } } else { TclEmitOpcode(INST_STORE_ARRAY_STK, envPtr); } } } else { TclEmitOpcode(INST_STORE_STK, envPtr); } /*
*/ TclEmitOpcode(INST_POP, envPtr); done: return code; }
And a little test, to show benefits of the bytecode, with four version of lreverse: the classic, one with the K operator, one with non bytecoded clear, and the last with bytecoded clear:
classic: 26629 microseconds per iteration K: 11130 microseconds per iteration clear: 9933 microseconds per iteration clearc: 6841 microseconds per iteration
--
AJD This functionality of K $x [set x ""] could be added as a new option on an existing Tcl command. To my mind [unset best fits the bill. A new flag could be added without breaking backwards compatability, say "-K" or "-value", or something better :-). AIUI, unset is not currently byte compiled, so this would need to be added to get the speedup of "clearc" detailed above.