TIP 445: Tcl_ObjType Utility Routines

Login
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        18-Mar-2016
Post-History:   
Tcl-Version:	8.7
Tcl-Branch:     tip-445
Vote-Summary:   Accepted 4/0/3
Votes-For:      DKF, KBK, JN, DGP
Votes-Against:  none
Votes-Present:  BG, FV, SL

Abstract

Proposes additional public routines useful for extensions that implement custom Tcl_ObjTypes.

Background

When an extension creates a custom Tcl_ObjType it needs to operate on the fields of the Tcl_Obj and the Tcl_ObjType structs.

Almost all of these operations have been nicely encapsulated in utility routines, so for example, an extension calls Tcl_GetString to make sure a value is set for objPtr->bytes, rather than worrying about the backing details of calling the routine objPtr->typePtr->updateStringProc (if present) for itself. Likewise Tcl_DuplicateObj routes processing to type-specific routines as needed.

There are gaps in this interface. Most glaring is the lack of any way to call the freeIntRepProc of an incumbent type other than directly through the typePtr field. Another missing bit is an encapsulated way to set the string rep without direct manipulation of the bytes and length fields. Within Tcl itself, there are internal utility macros TclFreeIntRep and TclInitStringRep for these tasks, but extensions have nothing.

Besides convenience, utility routines such as these improve chances for correctness, since they bring constraints into one place instead of many places. For example, the requirement that when objPtr->typePtr is not NULL, it must be paired with an appropriate objPtr->internalRep. The TclFreeIntRep macro has a history of fixing such bugs. A corresponding routine will offer the same benefit to extensions.

Proposal

Add to Tcl's stub table of public C routines a new routine

void Tcl_FreeInternalRep(Tcl_Obj* objPtr)

that performs precisely the same task as the existing internal macro TclFreeIntRep.

Add to Tcl's stub table of public C routines a new routine

char * Tcl_InitStringRep(Tcl_Obj* objPtr, const char* bytes, unsigned int numBytes)

that performs the function of the existing internal macro TclInitStringRep, but is extended to return a pointer to the string rep, and to accept NULL as a value for bytes. When bytes is NULL and objPtr has no string rep, an uninitialzed buffer of numBytes bytes is created for filling by the caller. When bytes is NULL and objPtr has a string rep, the string rep will be truncated to a length of numBytes bytes. When numBytes is greater than zero, and the returned pointer is NULL, that indicates a failure to allocate memory for the string representation. The caller may then choose whether to raise an error or panic.

Add to Tcl's stub table of public C routines a new routine

int Tcl_HasStringRep(Tcl_Obj* objPtr)

that returns a boolean indicating whether or not a string rep is currently stored in objPtr. This is used when the caller wants to act on objPtr differently depending on whether or not it is a pure value. Typically this only makes sense in an extension if it is already known that objPtr possesses an internal type that is managed by the extension.

Define a new public type

typedef union Tcl_ObjInternalRep {...} Tcl_ObjInternalRep

where the contents are exactly the existing contents of the union in the internalRep field of the Tcl_Obj struct. This definition permits us to pass internal representations and pointers to them as arguments and results in public routines.

Add to Tcl's stub table of public C routines a new routine

void Tcl_StoreInternalRep(Tcl_Obj* objPtr, const Tcl_ObjType* typePtr, const Tcl_ObjInternalRep* irPtr)

which stores in objPtr a copy of the internal representation pointed to by irPtr and sets its type to typePtr. When irPtr is NULL, this leaves objPtr without a representation for type typePtr.

Add to Tcl's stub table of public C routines a new routine

Tcl_ObjInternalRep* Tcl_FetchInternalRep(Tcl_Obj* objPtr, const Tcl_ObjType* typePtr)

which returns a pointer to the internal representation stored in objPtr that matches the requested type typePtr. If no such internal representation is in objPtr, return NULL.

Compatibility

These are new routines, so they have no compatibility concerns in the sense of cause trouble for existing working code.

They do help set up an improved compatibility scenario for the future however. Extensions that use these new routines to stop directly referring to the fields of the Tcl_Obj and Tcl_ObjType structs are prepared to support a source-compatible migration to a Tcl 9 that might then be free to make revisions to those structs.

Implementation

See the tip-445 branch.

Rejected Alternatives

At the time of its approval vote, this TIP proposed routines and a type with the names Tcl_FreeIntRep, Tcl_ObjIntRep, Tcl_StoreIntRep, and Tcl_FetchIntRep. Post-vote discussion on the TCLCORE mailing list raised the criticisms that IntRep was easily confused and typoed with the common Tcl_Interp variable name interp, and could also falsely suggest some relationship to integer types in the minds of many programmers. All names were changed to replace IntRep with InternalRep.

Copyright

This document has been placed in the public domain.