Tcl_Obj is the
C structure that implements every
Tcl value. The name is misleading.
Tcl_Value would better describe its purpose, but that term was already taken by
Tcl_CreateMathFunc().
AMG: Tcl 9 renames Tcl_Obj to Tcl_Value [
1].
- Tcl_Obj's are like storks. They have two legs, the internal representation and the string representation. They can stand on either leg, or on both.
- -- attributed to DKF
- Any Tcl_Obj that is not isomorphic to a string is a bug.
- -- dgp, Tcl Chatroom, 2015-07-01
See Also edit
- Creating and Using Tcl Handles in C Extensions
- How to embed Tcl in C applications
- Managing the reference count of Tcl objects
- Tcl_Obj Deep Copy
- Tcl_Obj refCount HOWTO
- Tcl_Obj types list
- Blessed Tcl_Obj Values
- A Tcl_Obj Command Machine Code Generator
- Tcl_Obj proposals
- Discussions of changes to the Tcl_Obj structure and its semantics are referred to
- Tcl_Obj vs Command
- Extending Tcl
- Islist Extension
- 32-bit integer overflow
- Category Tcl Library
- Tweezer
- Hack on Tcl objects from the script level.
- tclvalue
- An extension for Tcl 8.6+ to reflect the Tcl_Obj API into the script level.
Documentation edit
- An On-the-fly Bytecode Compiler for Tcl, Brian T. Lewis, 1996
- introduces Tcl_Obj
- official reference for Tcl_Obj and friends
- official reference for object types
Description edit
Tcl_Obj provides for both a string (UTF8) representation and an "internal" representation of the value, which is limited only by the constraints of the
C language itself. Each Tcl_Obj carries information about the type of its internal representation, and how to perform a conversion from the string representation to the internal representation, and vice-versa. In this way, the string becomes the universal intermediate representation for conversions between types. To enhance performance, Tcl knows how to perform direct conversions between certain often-used types.
A Tcl_Obj is is reference counted, and the allocator for it is very heavily tuned. It has a deeply unfortunate name, but the far more apt
Tcl_Value was previously taken for handling user-defined
expr functions - a now obsolete facility.
RS: thinks that the name is ok if one does not expect
OO features, class membership etc. Objects have been there long before OO, and the name is certainly not under a monopoly (I'd object against that ;-). But the basic feature of Tcl_Obj's is that they have a string representation and possibly a problem-oriented one, but each can be regenerated from the other (also if you define your obj Obj types). If such type conversions occur frequently, this costs performance - the so-called
shimmering occurs. E.g. see what happens to
$i below:
for {set i 0} {$i<10} {incr i} { #here we need the integer rep
puts [string length $i] ;#here the string rep..
puts [llength $i] ;# and here the list rep, so int rep goes away
}
CMcC: I've put together a summary page of
Tcl_Objs current for 8.4, containing information culled from the source.
A
Tcl_Obj is defined as a structure containing:
- an integer refCount
- representing the number of references to this Tcl_Obj
- a char *bytes
- being the string representation of the object (under the doctrine `everything's a string'). For a non-empty string, objv[i]->bytes points to Tcl_Alloc()ated memory. For an empty string, objv[i]->bytes points to a static char in the Tcl library that holds a NUL byte.
- an integer length
- being the length of the string representation in bytes (minus the extra byte for the terminating NUL)
- a pointer to a Tcl_ObjType
- which contains the type's name, and pointers to functions implementing the four fundamental operations which all Tcl_Obj instances are expected to implement.
- a union internalRep
- which is used to store up to two pointers of information which is opaque to Tcl.
Each
Tcl_ObjType structure contains the following four function pointers plus a name.
- freeIntRepProc
- Called to free any storage for the type's internal rep. NULL if the internal rep does not need freeing.
- dupIntRepProc
- Called to create a new object as a copy of an existing object; NULL indicates that the default strategy (memcpy the whole internalRep union) is sufficient.
- updateStringProc
- Called to update the string rep from the type's internal representation. (Not sure what NULL means for this; IME that's not an especially good idea. DKF: It's OK provided you never ever set the bytes field to NULL.)
- setFromAnyProc
- Called to convert the object's internal rep to this type. Frees the internal rep of the old type. Returns TCL_ERROR on failure. NULL indicates that objects of this type can't normally be created (typically because extra context is needed.)
Allocating a Tcl_Obj edit
DKF: You
must not allocate a
Tcl_Obj manually.
Always call
Tcl_NewObj (or one of its close relatives, such as
Tcl_NewIntObj()) to do it for you. This is because Tcl uses a special memory management engine for them that is tuned to be extra efficient -- useful because Tcl uses these things
a lot -- and that's only accessible through
Tcl_NewObj (or some wholly internal APIs that aren't exposed outside the Tcl library).
Reference Counting edit
AMG: In C extension code for Tcl you have several options with respect to reference counting:
- Manually invoke Tcl_IncrRefCount() on the Tcl_Objs you create. This protects them from being freed, but you're also responsible for calling Tcl_DecrRefCount() or else they'll leak.
- Give your Tcl_Objs to something that increments their reference counts. For example, put them in a Tcl variable, list, or dict. Don't call Tcl_IncrRefCount() unless your code is also retaining pointers that you expect to be valid sometime in the future.
- Don't fuss with reference counting because you're not the one creating the Tcl_Objs. This is the case when all you do is read arguments passed to your function which is implementing an extension command.
- Don't call Tcl_IncrRefCount() because you like to live dangerously and "know" that you're only passing your Tcl_Objs to things that won't pull the rug out from under you. Call Tcl_DecrRefCount() when you're done, and the Tcl_Objs will be freed when their refcounts go negative just as surely as when they go zero.
There's no way Tcl can remotely zap your Tcl_Objs with nonpositive refcount unless you've passed your Tcl_Obj pointers to Tcl library functions. Tcl doesn't keep a list of Tcl_Objs in existence, so it can't sweep.
Discarding the Internal Cached Interpretation of a Value edit
string length causes the internal cached interpretation of a value to be discarded :
% incr i
1
% ::tcl::unsupported::representation $i
value is a int with a refcount of 2, object pointer at 0x6000660e0, internal representation 0x1:0x600066320, string representation "1"
% string length $i
1
% ::tcl::unsupported::representation $i
value is a string with a refcount of 2, object pointer at 0x6000660e0, internal representation 0x6000ad6a0:0x600066320, string representation "1"
Data members of
Tcl_Obj, particularly
internalRep, can be mutated, so a
Tcl_Obj should be exclusively owned by one thread. See
Thread safety in tclZipfs.c.
Nested Tcl_Obj Structures edit
PYK 2018-05-12: Sometimes a
Tcl_Obj is stored in the internal representation of another
Tcl_Obj. This can lead to tricky issue such as
this memory leak in
foreach.
The fix involved clearing the internal representation of the nested
Tcl_Obj, but couldn't something else set the internal representation back to a problematic value again?