Tcl offers several techniques that can be used to implement static data in command procedures. This page is intended to present the pros and cons. ---- Example: Here is a command procedure for a simple Tcl command that makes use of a "static" value. Roughly, it's a constant value that each invocation of the command will use without changing, but a value that need not be created at all if the command is never evaluated. int OneObjCommand(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); return TCL_OK; } Tcl_CreateObjCommand(interp, "one", OneObjCommand, NULL, NULL); Note that each time [[one]] is evaluated, a new '''Tcl_Obj''' is created to hold the value '''1'''. Since Tcl is capable of managing shared '''Tcl_Obj'''s, other alternatives are possible that would set the result to be an additional reference to one shared '''Tcl_Obj''' rather than a new one each time. The alternatives differ mostly on where that shared '''Tcl_Obj''' is stored between calls. Why might we want an alternative? Most compelling reason is memory efficiency. Consider the script: for {set i 0} {$i < 1000000} {incr i} { set a($i) [one] } With the implementation of [[one]] above, 1 million '''Tcl_Obj''' structs have to be allocated. ---- '''Alternative 1: ClientData''' int OneObjCommand(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Tcl_SetObjResult(interp, (Tcl_Obj *)cd); return TCL_OK; } void OneDelete(ClientData cd) { Tcl_Obj *objPtr = (Tcl_Obj *)cd; Tcl_DecrRefCount(objPtr); } objPtr = Tcl_NewIntObj(1); Tcl_IncrObjCount(objPtr); Tcl_CreateObjCommand(interp, "one", OneObjCommand, (ClientData)objPtr, OneDelete); Here the shared '''Tcl_Obj''' with the value '''1''' is stuffed in the '''ClientData''' of the [[one]] command. One disadvantage of this alternative is that the shared '''Tcl_Obj''' is created whether or not [[one]] is ever called. For larger amounts of static data, that might be a waste worth avoiding. Another possible disadvantage might be conflict with other uses of the '''ClientData''' word that a command might have. ---- '''Alternative 2: One field in ClientData''' typedef struct OneData { Tcl_Obj *one; } OneData; int OneObjCommand(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { OneData *dataPtr = (OneData *)cd; if (dataPtr->one == NULL) { dataPtr->one = Tcl_NewIntObj(1); Tcl_IncrRefCount(dataPtr->one); } Tcl_SetObjResult(interp, dataPtr->one); return TCL_OK; } void OneDelete(ClientData cd) { OneData *dataPtr = (OneData *)cd; if (dataPtr->one != NULL) { Tcl_DecRefCount(dataPtr->one); } Tcl_Free(dataPtr); } dataPtr = Tcl_Alloc((int)sizeof(OneData)); Tcl_CreateObjCommand(interp, "one", OneObjCommand, (ClientData)dataPtr, OneDelete); ---- '''[DGP]'''