Tcl_Obj(3)
_________________________________________________________________
NAME
Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_Decr-
RefCount, Tcl_IsShared - 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_ListObjAppen-
dElement. The individual procedures are described along
with the data structures they manipulate.
Tcl's dual-ported objects provide a general-purpose mecha-
nism 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 manipu-
lated more efficiently. For example, a Tcl list is now
represented as an object that holds the list's string rep-
resentation 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 available. The compiler itself uses Tcl
objects to cache the instruction bytecodes resulting from
compiling scripts.
The two representations are a cache of each other and are
computed lazily. That is, each representation is only
computed when necessary, it is computed from the other
representation, and, once computed, it is saved. In addi-
tion, a change in one representation invalidates the other
one. As an example, a Tcl program doing integer calcula-
tions can operate directly on a variable's internal
machine integer representation without having to con-
stantly 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 repre-
sentation from the integer. Although objects contain an
internal representation, 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 representation is
fetched. Because of this representation invalidation and
regeneration, it is dangerous for extension writers to
access Tcl_Obj fields directly. It is better to access
Tcl_Obj information using procedures like Tcl_Get-
StringFromObj.
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 argu-
ments, 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 representa-
tion is controlled by its type. Seven types are prede-
fined 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
string representation, which is a counted or binary string
that may contain binary data with embedded null bytes.
bytes points to the first byte of the string representa-
tion. The length member gives the number of bytes. The
byte array must always have a null after the last byte, at
offset length; this allows string representations that do
not contain nulls to be treated as conventional null-ter-
minated C strings. C programs use Tcl_GetStringFromObj to
get an object's string representation. 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 rep-
resentation is invalid.
The internalRep union member holds an object's internal
representation. This is either a (long) integer, a dou-
ble-precision floating point number, a pointer to a value
containing additional information 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 refer-
ence count is a key responsibility of extension writers.
Reference counting is discussed below in the section STOR-
AGE 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 repre-
sentations. 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 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 example, Tcl_ListOb-
jReplace will modify an object's internal representation
and the next call to Tcl_GetStringFromObj will reflect
that change.
Representations are recomputed lazily for efficiency. A
change to one representation made by a procedure 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 con-
cerned with how this is done and simply use procedures
such as Tcl_GetBooleanFromObj or Tcl_ListObjIndex. Pro-
grammers that implement their own object types must check
for invalid representations and mark representations
invalid when necessary. The procedure Tcl_Invalidat-
eStringRep is used to mark an object's string representa-
tion invalid and to free any storage associated with the
old string representation.
Objects usually remain one type over their life, but occa-
sionally 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_StringObjAppend,
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 concerned about how this is
done. A procedure defined as part of the object type's
implementation creates 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 internal-
Rep.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 representation.
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 requirements. Refer-
ence 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_IncrRefCount 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 reference 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 procedures 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 ref-
erence 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_Decr-
RefCount to decrement each argument's reference count.
When an object's reference count drops to zero, Tcl_Decr-
RefCount 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. However, 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 lin-
sert. 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 increment-
ing the integer in its internal representation. If it is
shared, it needs to duplicate the object in order to avoid
accidently changing values in other data structures.
SEE ALSO
Tcl_ConvertToType, Tcl_GetIntFromObj, Tcl_ListObjAppen-
dElement, Tcl_ListObjIndex, Tcl_ListObjReplace, Tcl_Regis-
terObjType
KEYWORDS
internal representation, object, object creation, object
type, reference counting, string representation, type con-
version