Tcl_GetNumber(3tcl)

πŸ’– Tcl_GetNumber β€” bestie, let's read some numbers πŸ’–

okay so this is a page from the Tcl library procedures manual β€” section 3tcl, to be exact β€” and it's all about pulling an actual numeric value out of a Tcl value. two whole routines for you: Tcl_GetNumber and Tcl_GetNumberFromObj. pull up a chair, we're getting numbers out of things ✨


🌸 NAME 🌸

Tcl_GetNumber, Tcl_GetNumberFromObj β€” get a numeric value from a Tcl value. that's the whole job. get number. from thing. slay πŸ’…


✨ SYNOPSIS ✨

#include <tcl.h>

#include <tclTomMath.h>

int
Tcl_GetNumber(interp, bytes, numBytes, clientDataPtr, typePtr)

int
Tcl_GetNumberFromObj(interp, objPtr, clientDataPtr, typePtr)

two includes, bestie. don't forget the second one β€” tclTomMath.h is not decorative, it's where the big-int tea lives πŸ«–


πŸŽ€ ARGUMENTS πŸŽ€

  • Tcl_Interp *interp (out) β€” when it's not NULL, this is where the error info gets recorded if the value turns out to not be in any of the numeric formats Tcl recognizes. so like, it's the vibes-holder for bad news. pass NULL and Tcl just quietly keeps its opinions to itself πŸ™ˆ
  • const char *bytes (in) β€” points to the first byte of the string value we're examining. byte zero. the opening act ⭐
  • Tcl_Size numBytes (in) β€” how many bytes, starting at bytes, should get examined. and here's the lil plot twist: if numBytes is negative, then all the bytes get examined until the first NUL byte terminates the examination. so negative = "go until you hit the wall" 🧱
  • void * *clientDataPtr (out) β€” points to space where a pointer value may be written through which a numeric value is available to read. yes it's a pointer to a pointer. yes that's a lot of asterisks. we love her anyway πŸ’€
  • int *typePtr (out) β€” points to space where a value may be written reporting what type of numeric storage is available to read. it's the "which flavor of number are we dealing with" slot πŸ“
  • Tcl_Obj *objPtr (in) β€” a Tcl value to be examined. that's it. that's the whole arg πŸŽ€

πŸ‘‘ DESCRIPTION πŸ‘‘

these procedures let you, the caller, retrieve a numeric value from a Tcl value in a numeric format that Tcl recognizes. that's the mission statement, no cap.

Tcl recognizes so many things as numbers. like, genuinely a lot. some examples: "0", " +1", "-2 ", " 3 ", "0xdad1", "0d09", "1_000_000", "4.0", "1e-7", "NaN", or "Inf". (notice the spaces in there? yeah, Tcl is chill like that. underscores in numbers? also chill. hex and 0d-prefixed and float and scientific and the special guys β€” it's giving range 🌈)

when built-in Tcl commands act on these values as numbers, they get converted to a numeric representation so C code can handle them efficiently. and Tcl uses three C types to store these representations:

  1. double
  2. Tcl_WideInt
  3. mp_int

the tea on each of them β˜•:

  • double β€” provided by the C language standard. classic. iconic. no notes.
  • Tcl_WideInt β€” declared in the Tcl header file, tcl.h, and it's equivalent to the C standard type long long on most platforms. "on most platforms" is doing heavy lifting there, iykyk.
  • mp_int β€” declared in the header file tclTomMath.h, and implemented by the LibTomMath multiple-precision integer library, which is included with Tcl. big numbers, big energy πŸ”₯

πŸ¦‹ the two routines are literally the same, except πŸ¦‹

Tcl_GetNumber and Tcl_GetNumberFromObj perform the same function. they differ only in how the arguments present the Tcl value that's being examined:

  • Tcl_GetNumber accepts a counted string value in the arguments bytes and numBytes β€” or a NUL-terminated string value when numBytes is negative.
  • Tcl_GetNumberFromObj accepts the Tcl value in objPtr.

that's the entire difference. twins. fraternal, barely πŸ’œ


🧚 what actually happens when you call them 🧚

both routines examine the Tcl value and determine whether Tcl recognizes it as a number.

if it's not a number: both routines return TCL_ERROR, and β€” when interp is not NULL β€” they record an error message and an error code in interp. so if you passed NULL you get the error return and zero explanation. rude, but documented πŸ™ˆ

if Tcl does recognize the examined value as a number: both routines return TCL_OK, and they use the pointer arguments clientDataPtr and typePtr to report info you can use to retrieve the numeric representation.

heads up bestie: clientDataPtr and typePtr may not be NULL. like, that's not a suggestion, that's a requirement. do not test her.

both routines write to *clientDataPtr a pointer to the internal storage location where Tcl holds the converted numeric value. ✨


πŸ’… what goes into *typePtr πŸ’…

this is the part where it gets specific, so stay with me:

when the converted numeric value is stored as a double: a call to the math library routine isnan determines whether that value is not a number (NaN).

  • if it is NaN β†’ both Tcl_GetNumber and Tcl_GetNumberFromObj write the value TCL_NUMBER_NAN to *typePtr.
  • if it's not NaN β†’ both routines write the value TCL_NUMBER_DOUBLE to *typePtr.

these routines report different type values in these cases because Tcl_GetDoubleFromObj raises an error on NaN values. (that's the whole reason, bestie β€” it's about keeping the two paths distinguishable πŸ‘€)

for both of those reported type values, the storage pointer may be cast to type const double * and the double numeric value may be read through it.

when the converted numeric value is stored as a Tcl_WideInt: both Tcl_GetNumber and Tcl_GetNumberFromObj write the value TCL_NUMBER_INT to *typePtr. the storage pointer may be cast to type const Tcl_WideInt * and the Tcl_WideInt numeric value may be read through it. πŸŽ€

when the converted numeric value is stored as an mp_int: both Tcl_GetNumber and Tcl_GetNumberFromObj write the value TCL_NUMBER_BIG to *typePtr. the storage pointer may be cast to type const mp_int * and the mp_int numeric value may be read through it. πŸ‘‘


⭐ future-proofing, aka read the fine print ⭐

future releases of Tcl might expand or revise the recognition of values as numbers. if additional storage representations get adopted, these routines will add new values to be written to *typePtr to identify them.

so like β€” callers should think about how they should react to unknown values written to *typePtr. don't just assume it's one of the three you know. that's a vibe check for your own code, periodt.


πŸ’€ the DANGER ZONE (ok it's not that dramatic but please read this) πŸ’€

when callers of these routines read numeric values through the reported storage pointer, they are accessing memory that belongs to the Tcl library. the Tcl library has the power to overwrite or free this memory.

🚨 the storage pointer reported by a call to Tcl_GetNumber or Tcl_GetNumberFromObj should not be used after the same thread has possibly returned control to the Tcl library.

if you need longer-term access to the numeric value, copy it into memory that the caller controls. and listen β€” callers must not attempt to write through or free the storage pointer. it's not yours. don't touch. hands off 🫢


🌈 SEE ALSO 🌈

  • Tcl_GetDouble
  • Tcl_GetDoubleFromObj
  • Tcl_GetWideIntFromObj

go read those next, bestie, they're the cousins πŸ¦‹


πŸ’œ KEYWORDS πŸ’œ

double, double value, double type, integer, integer value, integer type, internal representation, value, value type, string representation


and that's the page!! you now know how to pull numbers out of Tcl values, which three C types can hold them, what lands in *typePtr, and β€” most importantly β€” that the storage pointer is borrowed, not gifted. copy it if you're keeping it. πŸ’–

this whole thing comes to you from the Tcl library procedures manual, Tcl 9.0 β€” that's the source and version, right there in the footer, and I'm folding it into this lil sign-off instead of a boring footer line. mwah. byeee πŸ‘‹βœ¨

πŸ“¦ where this page comes from