TIP 613: New INDEX_NULL_OK flag for Tcl_GetIndexFromObj*()

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Author:         Jan Nijtmans <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        09-Dec-2021
Post-History:   
Keywords:       Tcl Tcl_GetIndexFromObj() Tcl_GetIndexFromObjStruct()
Tcl-Version:    8.7
Tcl-Branch:     tip-613

Abstract

This TIP proposes a new INDEX_NULL_OK flag for Tcl_GetIndexFromObj*() as TCL_INDEX_NULL_OK, and allow other variable types (like enum, short, long, long long, both signed and unsigned) for the indexPtr variable.

It also proposes to implement the TCL_OPTION_NULL_OK flag in Tk for the options TK_OPTION_BOOLEAN, TK_OPTION_JUSTIFY and TK_OPTION_ANCHOR, in the same way as already present for TK_OPTION_RELIEF.

Rationale

In Tk, serveral options allow the empty string, but since Tcl_GetIndexFromObjStruct() cannot handle the empty string as input well, this results in special code in Tk to handle that. This is not always done correctly, e.g.:

$ wish8.6
% text .t
.t
% .t tag configure dummy -relief {}
% .t tag configure dummy -relief xxx
bad relief "xxx": must be flat, groove, raised, ridge, solid, or sunken
% .t tag configure dummy -wrap {}
% .t tag configure dummy -wrap foo
bad wrap "foo": must be char, none, word, or 
% 
So, the error-message doesn't even mention that "" is a valid value, or it forgets to quote the empty value.

The cause of the problem is here: the empty string is made part of a string array used by Tcl_GetIndexFromObj*().

The meaning of TCL_INDEX_NULL_OK is that Tcl_GetIndexFromObj*() no longer gives an error when indexPtr is supplied a NULL or "" argument, but it will return TCL_OK and provide the index "-1". This functionality can then be used by Tk:

$ wish8.7
% text .t
.t
% .t tag configure dummy -wrap {}
% .t tag configure dummy -wrap foo
bad wrap "foo": must be char, none, word, or ""
% 

The indexPtr parameter of Tcl_GetIndexFromObj*() always had to point to an integer variable, but this TIP changes the parameter to type void * which can point to almost anything. This is done by using a wrapper macro, which makes the sizeof() of the variable available to the function. So any scalar value, being an enum or some kind of integer (1-, 2-, 4- or 8-byte) will work.

For Tk, the enum's Tk_Anchor and Tk_Justify will get new members TK_ANCHOR_NULL resp. TK_JUSTIFY_NULL with value -1, equivalent with the already existing TK_RELIEF_NULL (which is not an enum for historical reasons). Without the TCL_OPTION_NULL_OK flag in the TK_OPTION_JUSTIFY and TK_OPTION_ANCHOR config information, everything functions as before, but when using the TCL_OPTION_NULL_OK flag, the new enum values become valid values for those configuration options.

For TK_OPTION_BOOLEAN, the new possible value, when using the TCL_OPTION_NULL_OK flag, is -1.

Caveat

Some extensions might have set the TCL_OPTION_NULL_OK flag already, even though it never worked. This might result in "" as possible option value, which was previously impossible, and what might lead to new unexpected behavior. Examples are this bug in Tk menu's and this bug in Themed Tk. Solution: the extension should no longer use the TCL_OPTION_NULL_OK flag, or expect Tcl 8.7 as a minimum and take care that the value -1 is handled properly.

Implementation

Available in the tip-613 branch.

There's a tip-613 branch in Tk as well, implementing the TCL_OPTION_NULL_OK flag for TK_OPTION_BOOLEAN, TK_OPTION_JUSTIFY and TK_OPTION_ANCHOR, using Tcl's TCL_INDEX_NULL_OK flag.

This branch targets 8.7.

Copyright

This document has been placed in the public domain.