[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 * command created by Tcl_ParseCommand. */ 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; } /* * Get the variable name token and push the name. */ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar); if (code != TCL_OK) { goto done; } /* * Emit instructions to get the variable. */ 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); } /* * Emit instructions to set the variable to empty string. */ 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); } /* * Pop the empty string, leaving the initial variable value. */ 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. [MS] notes that, at least for this usage, [unset] is a bad partner. [[K $x [[unset x]]]] does indeed return x's (unshared) value, but clears the complete variable - not just its value, it also frees memory structures and cleans up hash tables. Costly if you need to recreate the variable immediately after that, as is the case AFAIR in ''lreverse''. [AJD] My suggestion was that the new flag's behaviour would mimic the "clearc" ie. it wouldn't actually unset the variable in the ususal sense - which is is an excellent argument against adding it to unset :-) My reasoning is that the functionality is useful enough to be in the core but perhaps not enough to warrant a new command.