Tcl_Obj(3) Tcl Library Procedures Tcl_Obj(3)
____________________________________________________________________________________________________________
NAME
Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount, Tcl_IsShared, Tcl_Invalidat-eStringRep Tcl_InvalidateStringRep
eStringRep - manipulate Tcl objects
SYNOPSIS
#include <tcl.h>
Tcl_Obj *
Tcl_NewObj()
Tcl_Obj *
Tcl_DuplicateObj(objPtr)
Tcl_IncrRefCount(objPtr)
Tcl_DecrRefCount(objPtr)
int
Tcl_IsShared(objPtr)
Tcl_InvalidateStringRep(objPtr)
ARGUMENTS
Tcl_Obj *objPtr (in) Points to an object; must have been the result of a previous call to
Tcl_NewObj.
____________________________________________________________________________________________________________
INTRODUCTION
This man page presents an overview of Tcl objects and how they are used. It also describes generic
procedures for managing Tcl objects. These procedures are used to create and copy objects, and
increment and decrement the count of references (pointers) to objects. The procedures are used in
conjunction with ones that operate on specific types of objects such as Tcl_GetIntFromObj and
Tcl_ListObjAppendElement. The individual procedures are described along with the data structures
they manipulate.
Tcl's dual-ported objects provide a general-purpose mechanism for storing and exchanging Tcl values.
They largely replace the use of strings in Tcl. For example, they are used to store variable values,
command arguments, command results, and scripts. Tcl objects behave like strings but also hold an
internal representation that can be manipulated more efficiently. For example, a Tcl list is now
represented as an object that holds the list's string representation as well as an array of pointers
to the objects for each list element. Dual-ported objects avoid most runtime type conversions. They
also improve the speed of many operations since an appropriate representation is immediately avail-able. available.
able. The compiler itself uses Tcl objects to cache the instruction bytecodes resulting from compil-ing compiling
ing scripts.
The two representations are a cache of each other and are computed lazily. That is, each representa-tion representation
tion is only computed when necessary, it is computed from the other representation, and, once com-puted, computed,
puted, it is saved. In addition, a change in one representation invalidates the other one. As an
example, a Tcl program doing integer calculations can operate directly on a variable's internal
machine integer representation without having to constantly convert between integers and strings.
Only when it needs a string representing the variable's value, say to print it, will the program
regenerate the string representation from the integer. Although objects contain an internal repre-sentation, representation,
sentation, their semantics are defined in terms of strings: an up-to-date string can always be
obtained, and any change to the object will be reflected in that string when the object's string rep-resentation representation
resentation is fetched. Because of this representation invalidation and regeneration, it is danger-ous dangerous
ous for extension writers to access Tcl_Obj fields directly. It is better to access Tcl_Obj informa-tion information
tion using procedures like Tcl_GetStringFromObj and Tcl_GetString.
Objects are allocated on the heap and are referenced using a pointer to their Tcl_Obj structure.
Objects are shared as much as possible. This significantly reduces storage requirements because some
objects such as long lists are very large. Also, most Tcl values are only read and never modified.
This is especially true for procedure arguments, which can be shared between the caller and the
called procedure. Assignment and argument binding is done by simply assigning a pointer to the
value. Reference counting is used to determine when it is safe to reclaim an object's storage.
Tcl objects are typed. An object's internal representation is controlled by its type. Seven types
are predefined in the Tcl core including integer, double, list, and bytecode. Extension writers can
extend the set of types by using the procedure Tcl_RegisterObjType .
THE TCL_OBJ STRUCTURE
Each Tcl object is represented by a Tcl_Obj structure which is defined as follows.
typedef struct Tcl_Obj {
int refCount;
char *bytes;
int length;
Tcl_ObjType *typePtr;
union {
long longValue;
double doubleValue;
VOID *otherValuePtr;
struct {
VOID *ptr1;
VOID *ptr2;
} twoPtrValue;
} internalRep;
} Tcl_Obj;
The bytes and the length members together hold an object's UTF-8 string representation, which is a |
counted string not containing null bytes (UTF-8 null characters should be encoded as a two byte |
sequence: 192, 128.) bytes points to the first byte of the string representation. The length member |
gives the number of bytes. The byte array must always have a null byte after the last data byte, at |
offset length; this allows string representations to be treated as conventional null-terminated C |
strings. C programs use Tcl_GetStringFromObj and Tcl_GetString to get an object's string representa-tion. representation.
tion. If bytes is NULL, the string representation is invalid.
An object's type manages its internal representation. The member typePtr points to the Tcl_ObjType
structure that describes the type. If typePtr is NULL, the internal representation is invalid.
The internalRep union member holds an object's internal representation. This is either a (long)
integer, a double-precision floating point number, a pointer to a value containing additional infor-mation information
mation needed by the object's type to represent the object, or two arbitrary pointers.
The refCount member is used to tell when it is safe to free an object's storage. It holds the count
of active references to the object. Maintaining the correct reference count is a key responsibility
of extension writers. Reference counting is discussed below in the section STORAGE MANAGEMENT OF
OBJECTS.
Although extension writers can directly access the members of a Tcl_Obj structure, it is much better
to use the appropriate procedures and macros. For example, extension writers should never read or
update refCount directly; they should use macros such as Tcl_IncrRefCount and Tcl_IsShared instead.
A key property of Tcl objects is that they hold two representations. An object typically starts out
containing only a string representation: it is untyped and has a NULL typePtr. An object containing
an empty string or a copy of a specified string is created using Tcl_NewObj or Tcl_NewStringObj
respectively. An object's string value is gotten with Tcl_GetStringFromObj or Tcl_GetString and
changed with Tcl_SetStringObj. If the object is later passed to a procedure like Tcl_GetIntFromObj
that requires a specific internal representation, the procedure will create one and set the object's
typePtr. The internal representation is computed from the string representation. An object's two
representations are duals of each other: changes made to one are reflected in the other. For exam-ple, example,
ple, Tcl_ListObjReplace will modify an object's internal representation and the next call to Tcl_Get-StringFromObj Tcl_GetStringFromObj
StringFromObj or Tcl_GetString will reflect that change.
Representations are recomputed lazily for efficiency. A change to one representation made by a pro-cedure procedure
cedure such as Tcl_ListObjReplace is not reflected immediately in the other representation. Instead,
the other representation is marked invalid so that it is only regenerated if it is needed later.
Most C programmers never have to be concerned with how this is done and simply use procedures such as
Tcl_GetBooleanFromObj or Tcl_ListObjIndex. Programmers that implement their own object types must
check for invalid representations and mark representations invalid when necessary. The procedure
Tcl_InvalidateStringRep is used to mark an object's string representation invalid and to free any
storage associated with the old string representation.
Objects usually remain one type over their life, but occasionally an object must be converted from
one type to another. For example, a C program might build up a string in an object with repeated
calls to Tcl_AppendToObj, and then call Tcl_ListObjIndex to extract a list element from the object.
The same object holding the same string value can have several different internal representations at
different times. Extension writers can also force an object to be converted from one type to another
using the Tcl_ConvertToType procedure. Only programmers that create new object types need to be con-cerned concerned
cerned about how this is done. A procedure defined as part of the object type's implementation cre-ates creates
ates a new internal representation for an object and changes its typePtr. See the man page for
Tcl_RegisterObjType to see how to create a new object type.
EXAMPLE OF THE LIFETIME OF AN OBJECT
As an example of the lifetime of an object, consider the following sequence of commands:
set x 123
This assigns to x an untyped object whose bytes member points to 123 and length member contains 3.
The object's typePtr member is NULL.
puts "x is $x"
x's string representation is valid (since bytes is non-NULL) and is fetched for the command.
incr x
The incr command first gets an integer from x's object by calling Tcl_GetIntFromObj. This procedure
checks whether the object is already an integer object. Since it is not, it converts the object by
setting the object's internalRep.longValue member to the integer 123 and setting the object's typePtr
to point to the integer Tcl_ObjType structure. Both representations are now valid. incr increments
the object's integer internal representation then invalidates its string representation (by calling
Tcl_InvalidateStringRep) since the string representation no longer corresponds to the internal repre-sentation. representation.
sentation.
puts "x is now $x"
The string representation of x's object is needed and is recomputed. The string representation is
now 124. and both representations are again valid.
STORAGE MANAGEMENT OF OBJECTS
Tcl objects are allocated on the heap and are shared as much as possible to reduce storage require-ments. requirements.
ments. Reference counting is used to determine when an object is no longer needed and can safely be
freed. An object just created by Tcl_NewObj or Tcl_NewStringObj has refCount 0. The macro Tcl_Incr-RefCount Tcl_IncrRefCount
RefCount increments the reference count when a new reference to the object is created. The macro
Tcl_DecrRefCount decrements the count when a reference is no longer needed and, if the object's ref-erence reference
erence count drops to zero, frees its storage. An object shared by different code or data structures
has refCount greater than 1. Incrementing an object's reference count ensures that it won't be freed
too early or have its value change accidently.
As an example, the bytecode interpreter shares argument objects between calling and called Tcl proce-dures procedures
dures to avoid having to copy objects. It assigns the call's argument objects to the procedure's
formal parameter variables. In doing so, it calls Tcl_IncrRefCount to increment the reference count
of each argument since there is now a new reference to it from the formal parameter. When the called
procedure returns, the interpreter calls Tcl_DecrRefCount to decrement each argument's reference
count. When an object's reference count drops less than or equal to zero, Tcl_DecrRefCount reclaims
its storage. Most command procedures do not have to be concerned about reference counting since they
use an object's value immediately and don't retain a pointer to the object after they return. How-ever, However,
ever, if they do retain a pointer to an object in a data structure, they must be careful to increment
its reference count since the retained pointer is a new reference.
Command procedures that directly modify objects such as those for lappend and linsert must be careful
to copy a shared object before changing it. They must first check whether the object is shared by
calling Tcl_IsShared. If the object is shared they must copy the object by using Tcl_DuplicateObj;
this returns a new duplicate of the original object that has refCount 0. If the object is not
shared, the command procedure "owns" the object and can safely modify it directly. For example, the
following code appears in the command procedure that implements linsert. This procedure modifies the
list object passed to it in objv[1] by inserting objc-3 new elements before index.
listPtr = objv[1];
if (Tcl_IsShared(listPtr)) {
listPtr = Tcl_DuplicateObj(listPtr);
}
result = Tcl_ListObjReplace(interp, listPtr, index, 0, (objc-3), &(objv[3]));
As another example, incr's command procedure must check whether the variable's object is shared
before incrementing the integer in its internal representation. If it is shared, it needs to dupli-cate duplicate
cate the object in order to avoid accidently changing values in other data structures.
SEE ALSO
Tcl_ConvertToType, Tcl_GetIntFromObj, Tcl_ListObjAppendElement, Tcl_ListObjIndex, Tcl_ListObjReplace,
Tcl_RegisterObjType
KEYWORDS
internal representation, object, object creation, object type, reference counting, string representa-tion, representation,
tion, type conversion
Tcl 8.1 Tcl_Obj(3)
|