Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount,
Tcl_IsShared, Tcl_InvalidateStringRep - 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 proce-
dures 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 stor-
ing 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 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 immedi-
ately 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,
StringFromObj 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 con-
trolled 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_Get-
String 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 type-
Ptr 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.
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_Set-
StringObj. If the object is later passed to a procedure like Tcl_Get-
IntFromObj that requires a specific internal representation, the proce-
dure will create one and set the object's typePtr. The internal repre-
sentation 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_ListObjReplace will modify an
object's internal representation and the next call to Tcl_GetStringFro-
mObj or Tcl_GetString 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 concerned with
how this is done and simply use procedures such as Tcl_GetBooleanFro-
mObj 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 stor-
age 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 ele-
ment 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 program-
mers that create new object types need to be concerned about how this
is done. A procedure defined as part of the object type's implementa-
tion 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
again valid.
STORAGE MANAGEMENT OF OBJECTS
Tcl objects are allocated on the heap and are shared as much as possi-
ble to reduce storage requirements. 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_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
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 refer-
ence count. When an object's reference count drops less than or equal
to zero, Tcl_DecrRefCount reclaims its storage. Most command proce-
dures 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 ref-
erence count since the retained pointer is a new reference.
Command procedures that directly modify objects such as those for lap-
pend and linsert must be careful to copy a shared object before chang-
ing 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 duplicate the
object in order to avoid accidently changing values in other data
structures.
Man(1) output converted with
man2html
|