Tcl_Obj(3) Tcl Library Procedures Tcl_Obj(3)______________________________________________________________________________NAME
Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount,
Tcl_IsShared, Tcl_InvalidateStringRep - manipulate Tcl values
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 a value; must have been the
result of a previous call to Tcl_NewObj.
_________________________________________________________________INTRODUCTION
This man page presents an overview of Tcl values (called Tcl_Objs for
historical reasons) and how they are used. It also describes generic
procedures for managing Tcl values. These procedures are used to cre‐
ate and copy values, and increment and decrement the count of refer‐
ences (pointers) to values. The procedures are used in conjunction
with ones that operate on specific types of values such as Tcl_GetInt‐
FromObj and Tcl_ListObjAppendElement. The individual procedures are
described along with the data structures they manipulate.
Tcl's dual-ported values 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 values 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
a value that holds the list's string representation as well as an array
of pointers to the values for each list element. Dual-ported values
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 values to cache the instruc‐
tion 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 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 representa‐
tion 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 values 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 value will be reflected in
that string when the value'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_GetStringFro‐
mObj and Tcl_GetString.
Values are allocated on the heap and are referenced using a pointer to
their Tcl_Obj structure. Values are shared as much as possible. This
significantly reduces storage requirements because some values 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 a value's storage.
Tcl values are typed. A value's internal representation is controlled
by its type. Several types are predefined in the Tcl core including
integer, double, list, and bytecode. Extension writers can extend the
set of types by defining their own Tcl_ObjType structs.
THE TCL_OBJ STRUCTURE
Each Tcl value is represented by a Tcl_Obj structure which is defined
as follows.
typedef struct Tcl_Obj {
int refCount;
char *bytes;
int length;
const Tcl_ObjType *typePtr;
union {
long longValue;
double doubleValue;
void *otherValuePtr;
Tcl_WideInt wideValue;
struct {
void *ptr1;
void *ptr2;
} twoPtrValue;
struct {
void *ptr;
unsigned long value;
} ptrAndLongRep;
} internalRep;
} Tcl_Obj;
The bytes and the length members together hold a value'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 a value's string representation. If bytes is NULL, the
string representation is invalid.
A value's type manages its internal representation. The member typePtr
points to the Tcl_ObjType structure that describes the type. If type‐
Ptr is NULL, the internal representation is invalid.
The internalRep union member holds a value's internal representation.
This is either a (long) integer, a double-precision floating-point num‐
ber, a pointer to a value containing additional information needed by
the value's type to represent the value, a Tcl_WideInt integer, two
arbitrary pointers, or a pair made up of an unsigned long integer and a
pointer.
The refCount member is used to tell when it is safe to free a value's
storage. It holds the count of active references to the value. Main‐
taining the correct reference count is a key responsibility of exten‐
sion writers. Reference counting is discussed below in the section
STORAGE MANAGEMENT OF VALUES.
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 values is that they hold two representations. A
value typically starts out containing only a string representation: it
is untyped and has a NULL typePtr. A value containing an empty string
or a copy of a specified string is created using Tcl_NewObj or Tcl_New‐
StringObj respectively. A value's string value is gotten with Tcl_Get‐
StringFromObj or Tcl_GetString and changed with Tcl_SetStringObj. If
the value is later passed to a procedure like Tcl_GetIntFromObj that
requires a specific internal representation, the procedure will create
one and set the value's typePtr. The internal representation is com‐
puted from the string representation. A value's two representations
are duals of each other: changes made to one are reflected in the
other. For example, Tcl_ListObjReplace will modify a value's internal
representation and the next call to Tcl_GetStringFromObj or Tcl_Get‐
String 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 value
types must check for invalid representations and mark representations
invalid when necessary. The procedure Tcl_InvalidateStringRep is used
to mark a value's string representation invalid and to free any storage
associated with the old string representation.
Values usually remain one type over their life, but occasionally a
value must be converted from one type to another. For example, a C
program might build up a string in a value with repeated calls to
Tcl_AppendToObj, and then call Tcl_ListObjIndex to extract a list ele‐
ment from the value. The same value holding the same string value can
have several different internal representations at different times.
Extension writers can also force a value to be converted from one type
to another using the Tcl_ConvertToType procedure. Only programmers
that create new value types need to be concerned about how this is
done. A procedure defined as part of the value type's implementation
creates a new internal representation for a value and changes its type‐
Ptr. See the man page for Tcl_RegisterObjType to see how to create a
new value type.
EXAMPLE OF THE LIFETIME OF A VALUE
As an example of the lifetime of a value, consider the following
sequence of commands:
set x 123
This assigns to x an untyped value whose bytes member points to 123 and
length member contains 3. The value'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 value by calling
Tcl_GetIntFromObj. This procedure checks whether the value is already
an integer value. Since it is not, it converts the value by setting
the value's internalRep.longValue member to the integer 123 and setting
the value's typePtr to point to the integer Tcl_ObjType structure.
Both representations are now valid. incr increments the value's inte‐
ger 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 value is needed and is recomputed.
The string representation is now 124 and both representations are again
valid.
STORAGE MANAGEMENT OF VALUES
Tcl values are allocated on the heap and are shared as much as possible
to reduce storage requirements. Reference counting is used to deter‐
mine when a value is no longer needed and can safely be freed. A value
just created by Tcl_NewObj or Tcl_NewStringObj has refCount 0. The
macro Tcl_IncrRefCount increments the reference count when a new refer‐
ence to the value is created. The macro Tcl_DecrRefCount decrements
the count when a reference is no longer needed and, if the value's ref‐
erence count drops to zero, frees its storage. A value shared by dif‐
ferent code or data structures has refCount greater than 1. Increment‐
ing a value's reference count ensures that it will not be freed too
early or have its value change accidentally.
As an example, the bytecode interpreter shares argument values between
calling and called Tcl procedures to avoid having to copy values. It
assigns the call's argument values 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 a value'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 a
value's value immediately and do not retain a pointer to the value
after they return. However, if they do retain a pointer to a value 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 values such as those for lap‐
pend and linsert must be careful to copy a shared value before changing
it. They must first check whether the value is shared by calling
Tcl_IsShared. If the value is shared they must copy the value by using
Tcl_DuplicateObj; this returns a new duplicate of the original value
that has refCount 0. If the value is not shared, the command procedure
“owns” the value 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 value 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 value is shared before incrementing the integer in its
internal representation. If it is shared, it needs to duplicate the
value in order to avoid accidentally changing values in other data
structures.
SEE ALSOTcl_ConvertToType(3), Tcl_GetIntFromObj(3), Tcl_ListObjAppendEle‐
ment(3), Tcl_ListObjIndex(3), Tcl_ListObjReplace(3), Tcl_RegisterObj‐
Type(3)KEYWORDS
internal representation, value, value creation, value type, reference
counting, string representation, type conversion
Tcl 8.5 Tcl_Obj(3)