TIP #182: ADD [EXPR BOOL] MATH FUNCTION ========================================= Version: $Revision: 1.16 $ Author: Joe Mistachkin Don Porter State: Final Type: Project Tcl-Version: 8.5 Vote: Done Created: Tuesday, 23 March 2004 URL: https://tip.tcl-lang.org182.html Post-History: ------------------------------------------------------------------------- ABSTRACT ========== This TIP proposes a new *expr* math function *bool()*. BACKGROUND ============ Several of the Tcl/Tk built-in commands make use of the notion of a Boolean value, a value that can be either true or false. Boolean values show up in control commands like *if* and *while*, and they also are used to enable/disable certain features, as in *tcltest::singleProcess $bool* and *namespace ensemble configure $ens -prefixes $bool*. There have long been two distinct notions of the set of string values that are recognized as boolean values. The *Tcl_GetBoolean()* routine recognizes the following strings and their unique prefixes, in all case variations, and /nothing else/ as valid boolean values: *0*, *1*, *yes*, *no*, *true*, *false*, *on*, *off*. Several script-level commands are implemented by calls to *Tcl_GetBoolean*, and also recognize only this limited set of string values as boolean values. Examples include *string is boolean*, *string is true*, *string is false*, and *fconfigure $chan -blocking*. Examples from Tk include configuration options of the *canvas*, *text*, and *scrollbar* that expect boolean values. The *Tcl_ExprBoolean()* routine interprets the result of an expression evaluation as a boolean. It recognizes all the values recognized by *Tcl_GetBoolean()*, but it also recognizes all numeric values as booleans as well. Any string which Tcl can interpret as any kind of number is a boolean according to *Tcl_ExprBoolean()* with the non-zero numbers seen as true, and others seen as false. Script-level commands such as *if* and *while* have adopted this view of booleans, so a script like *while {[incr x -1]} {}* works as expected. It also means the script *if 0x1 {}* is perfectly acceptable, even though *string is boolean 0x1* reports that *0x1* is not a boolean. The *Tcl_GetBooleanFromObj()* routine arrived in Tcl 8.0, and contrary to what its name might suggest, it was and is not an Obj-ified form of *Tcl_GetBoolean*. Instead, *Tcl_GetBooleanFromObj()* adopted the *Tcl_ExprBoolean* understanding of what was and was not a boolean value. Over time as more Tcl and Tk commands were Obj-ified, it was natural to replace *Tcl_GetBoolean* calls with *Tcl_GetBooleanFromObj* and in the process several commands have come to accept a broader class of boolean values than they once did. For example, % info patch 7.6p2 % clock format 0 -gmt 0x1 expected boolean value but got "0x1" % info patch 8.0.5 % clock format 0 -gmt 0x1 Thu Jan 01 00:00:00 GMT 1970 Another (accidental?) change in behavior in *Tcl_LinkVar()* sneaked in with the [TIP #72] changes between Tcl 8.3 and Tcl 8.4. A linked variable of type *TCL_LINK_BOOLEAN* now allows the Tcl variable to hold any numeric value, while in pre-8.4 releases of Tcl, only those values acceptable to *Tcl_GetBoolean* were permitted. Tcl's built-in math functions include three that are devoted to "casting" operations, *int()*, *double()*, and *wide()*. In each case, the result of the function is a string that passes the corresponding *string is* test. For example, string is integer [expr {int($x)}] will either return *1*, or raise an error; it will never return *0*. PROPOSED CHANGE ================= Add a new built-in unary math function *bool()* that accepts all values accepted by *Tcl_GetBooleanFromObj()* and returns one of the boolean values *0* or *1*, which are acceptable to *Tcl_GetBoolean*. With that definition in place, string is boolean [expr {bool($x)}] will either return *1*, or raise an error; it will never return *0*. REFERENCE IMPLEMENTATION ========================== A "quick and dirty" implementation would be (see [TIP #232]): proc ::tcl::matchfunc::bool x {expr {!!$x}} A preferred implementation is at Tcl Patch 1165062. [] The preferred implementation has somewhat nicer error message reporting, and has greater potential for bytecode performance improvements. RATIONALE =========== First, this simply makes a nice parallel with the existing "casting" functions. It does away with the surprise expressed by some that a language making use of doubles, integers, and booleans provides *double()* and *int()*, but not *bool()*. Second, because we have this bifurcated opinion about what values really count as boolean values, the proposed math function provides to the script level a way to safely accept booleans in the broader sense, even if using an interface that may be narrow. fconfigure $chan -blocking [expr {bool($value)}] This is, of course, equivalent to fconfigure $chan -blocking [expr {!!$value}] but should be easier on the code-reading eyes. COPYRIGHT =========== This document has been placed in the public domain. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows