TIP #215: MAKE [INCR] AUTO-INITIALIZE UNDEFINED VARIABLES =========================================================== Version: $Revision: 1.11 $ Author: Andreas Leitgeb Don Porter State: Final Type: Project Tcl-Version: 8.5 Vote: Done Created: Wednesday, 25 August 2004 URL: https://tip.tcl-lang.org215.html Post-History: ------------------------------------------------------------------------- ABSTRACT ========== Unlike *append* and *lappend*, *incr* currently does not auto-create yet-undefined variables. This TIP proposes to make *incr*'s behaviour in this regard more like the aforementioned commands. RATIONALE =========== A quite common task is counting the number of occurrences of items in a given list. The usual solution is to iterate the list, and for each item, increment the associated value in a tcl-array. As of now this requires a separate step of determining the not-yet-existence and eventual initialization to 0 or alternatively *catch*'ing errors from *incr* and setting the variable, if an error was raised. If we instead alter *incr* to treat non-existant variables as if they contained the value 0, this would be more like the auto-initializing behaviour of *append* and *lappend*, and would make writing code that does this sort of summing up much easier. It is also very similar to the way that the *dict incr* subcommand operates. NO CHANGE FOR VARIABLES THAT CONTAIN NON-INTEGERS =================================================== Just as *lappend* does complain if passed a variable whose value is an invalid list (e.g. a single open-brace), so it appears reasonable for *incr* to still throw an error if the variable contains something that is not a number. The empty string is invalid as an operand for *expr*'s integer operators, so it should remain illegal to *incr* an existing variable that contains an empty string. FURTHER SPECIAL CASES ======================= If a variable passed to incr is not yet existing, but linked to some other not-yet existing var, or if it is traced, then of course it would add flesh to that existing husk. Care should be taken that any write traces only trigger once (like for *lappend*), not twice (as in: for initializing and then for incrementing). PROPOSAL ========== The current *incr* command behaves like the following proc: proc incr {varName {increment 1}} { upvar 1 $varName v return [set v [expr {$v + $increment}]] ;# read/write trace } It is proposed to make *incr* behave like the following modified proc: proc incr {varName {increment 1}} { upvar 1 $varName v set code [catch {set v} value] ;# read trace if {$code} { return [set v $increment] ;# write trace } return [set v [expr {$value + $increment}]] ;# write trace } Please note these example procs are meant to illustrate the proposed change only. They do not fully reflect the exact function of *incr* (limiting to only integer values, for example). For a more concrete illustration of the proposal, see the reference implementation, SF patch #1413115 []. DISCUSSION ============ There have been comments that *incr* modified as proposed would lose one means of typo-detection: If the varname is mistyped, then instead of throwing an error, it would turn into a noop. My (TIP-originator) answer to this: relying on thrown exceptions for mistyped varnames is a very weak strategy in dynamic (non-compiled) languages like tcl, anyway, because it would require a 100%-test-coverage of execution-paths. Nevertheless, this shouldn't exclude discussion about less typo-forgiving alternatives: Proposed (by others) alternative #1: make *incr* accept a second optional argument /init/ which, if specified, will cause *incr* to accept non-existent variables and initialize them with the value /init/. One disadvantage of this behaviour is, that it is at odds with append and lappend behaviour, which would rather imply that if more than one argument is given after the varname, then each of them would be added in row. Another con would be, that it would not be intuitive, whether the resulting value would be /init/ or (/init/ + /increment/). Similar alternatives mentioning new option *-initValue* are over-verbose imho. Another way to partially reduce this proposal's forgiveness would be to allow autoinitialization only for array-elements. This looks grossly unorthogonal at first sight, but addresses the fact, that the primary reason for TIP 215 was counting occurrences of strings, which are then made keys in an array. The danger of mistyped array-keys is surely much lower than that of mistyped variable names. See [TIP #224] COPYRIGHT =========== This document has been placed in the public domain. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows