TIP 638: New public routines Tcl_GetNumber(FromObj)

Login
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        18-Sep-2022
Tcl-Version:    8.7
Tcl-Branch:	tip-getnumber
    Vote-Summary:   Accepted 6/0/0
    Votes-For:      DP, JN, SL, FV, KK, KW
    Votes-Against:  none
    Votes-Present:  none

Abstract

This TIP proposes new public routines Tcl_GetNumber and Tcl_GetNumberFromObj.

Background

Development of Tcl 8.5 included major reworkings of Tcl's handling of numeric values, including TIPs [237], [249], and more. One routine that arose out of that development work was the internal routine,

int TclGetNumberFromObj(Tcl_Interp* interp, Tcl_Obj* objPtr, ClientData* clientDataPtr, int* typePtr) .

It is a utility routine that can pull any numeric value from a Tcl value, following Tcl's own specifications for numeric formats. It is useful when a caller wants to accept multiple varieties of numeric values, so that a more specific routine like Tcl_GetDoubleFromObj is not sufficient. It is used effectively in many places within Tcl's own implementation. It has potential value for extensions and applications as well.

An examination of the Tk source code and other extensions reveals that when they break the encapsulation of Tcl's built-in Tcl_ObjTypes, it is often for the purpose of gaining access to numeric values. A supported public routine to achieve that aim will pave the way to eliminate encapsulation breaking.

Specification

Convert the exising internal routine TclGetNumberFromObj into its public counterpart Tcl_GetNumberFromObj.

Create the additional public routine,

int Tcl_GetNumber(Tcl_Interp* interp, const char * bytes, ptrdiff_t numBytes, ClientData* clientDataPtr, int* typePtr)

which has the same functionality, but presents the value to be examined as a counted string (bytes, numBytes) instead of as objPtr. This alternative form is parallel to the alternative forms of routines like Tcl_GetDouble and Tcl_GetDoubleFromObj.

Usage

When internal routine TclParseNumber successfully parses a numeric value, it stores the result in one of three forms of storage. It can be stored as a double, as a Tcl_WideInt, or as an mp_int. The proposed routines use integer values to represent these possibilities, TCL_NUMBER_DOUBLE, TCL_NUMBER_INT, and TCL_NUMBER_BIG, respectively. The routines use an additional integer value, TCL_NUMBER_NAN when the value is NaN stored in a double. This case is helpful because Tcl_GetDoubleFromObj is defined to raise an error on a NaN value.

The proposed routines examine the presented value, whether as an objPtr or as a counted string, to determine whether it matches one of the numeric formats recognized by Tcl. This recognition might have already taken place and been recorded in the internal representation of objPtr, or it might be discovered via a call to TclParseNumber. If the presented value is not a numeric value at all, the proposed routines return TCL_ERROR and when interp is not NULL, a suitable error message and error code are recorded in it.

When the presented value is recognized as a numeric value, the proposed routines return TCL_OK and write to *typePtr the TCL_NUMBER_* integer value indicating what kind of storage holds the value. They also write to *clientDataPtr a pointer to that storage in the memory managed by and belonging to Tcl. The caller can then use the value of *typePtr to determine how to cast the pointer in *clientDataPtr properly to be able to read the stored value.

The pointer value recovered by the caller of Tcl_GetNumber points to memory belonging to Tcl, which may free it or overwrite it. The caller should read the value from this pointer before any more calls into Tcl routines in the same thread. Any long term need for this value will require a copy.

Compatibility

These are new public routines. They should create no compatibility issues.

Extensibility

If Tcl ever expands the set of numeric formats it recognizes in some way that requires a new category of storage, these routines may be expanded to return additional integer values indicating the new storage options. Callers may wish to handle unrecognized type values as preparation for that possibility.

Addendum

After TIP #660 was accepted, a lot of functions changed from using size_t to ptrdiff_t parameters. In order to prevent confusion, this change has been adapted in the TIP text above as well.

Reference Implementation

Under development on the tip-getnumber branch.

Copyright

This document has been placed in the public domain.