TIP #408: ALLOW ANY COMMAND FOR EXPR FUNCTIONS ================================================ Version: $Revision: 1.1 $ Author: Brian Griffin State: Draft Type: Project Tcl-Version: 8.7 Vote: Pending Created: Friday, 17 August 2012 URL: https://tip.tcl-lang.org408.html Post-History: ------------------------------------------------------------------------- ABSTRACT ========== Proposed expansion of what constitutes a function in an *expr* expression. RATIONALE: NESTED EXPR CALLS ============================== The *expr* command in Tcl is the only way to perform math and comparison operations. Tcl's variable and command substitution rules allow for great flexibility, although the syntax does not lead to great readability, especially due to the ordering imposed on substitutions. For example, in the expression: expr {[lindex $data $start] > 4} the command substitution ([...]) is performed before the expression can be parsed for evaluation, and, in order for the command substitution to be parsed, the variable substitution ($) must be performed. The consequences of this ordering means that arguments to commands cannot themselves be expressions unless the argument is itself a command substitution involving *expr*. This means, for example, that to compute an index value, *expr* must be recursively called: expr {[lindex $data [expr {$start + 2}]] > 4} However, when using a math function, the command substitution ordering does not apply since the function is part of the expression syntax: expr {pow($x + 2, 2)} It seems reasonable and useful if any Tcl command can be called using function syntax: expr {lindex($data, $start + 2) > 4} The common command substitution pattern has lead many developers to end up writing things like: if {[expr {$a+$b}] > 7} ... In hindsight, such statements look ridiculous, but it works and it follows the same pattern as the *lindex* case above. If subexpressions could be evaluated directly by the enclosing *expr* operations, this would greatly simplify the overall expression and make it more readable and thereby more maintainable, and hopefully, less error prone. The goal here is to reduce the instances of recursive *expr* calls in an expression. It seems overly complex and confusing to read, and to have to use command substitution syntax inside what is already an *expr* operation. PROPOSED CHANGES ================== The proposal is to simply apply normal Tcl command resolution rules to *expr* functions. The one caveat is that *tcl::mathfunc* namespace is always searched first. I see this as a continuation to [TIP #232]. REJECTED ALTERNATIVES ======================= This can already be accomplished today by creating alias functions in the *tcl::mathfunc* namespace, but this mechanism is awkward in that: 1. It must be defined beforehand for the set of commands used or intended to be used in expressions, 2. For OO and namespace code, some specialized duplication is also required, and 3. It can lead to confusion when it's not clear why some commands work as functions and others don't. PROOF OF CONCEPT ================== (Thanks and credit to Frédéric Bonnet) A quick & dirty proof of concept with unknown handlers: proc mathproc {cmd args} { if {[namespace qualifiers $cmd] eq "tcl::mathfunc"} { return [uplevel [list [namespace tail $cmd]] $args] } uplevel [list ::unknown $cmd] $args } namespace unknown mathproc set l [expr {list(1,2,3)}] => 1 2 3 expr {lindex($l,2)} => 3 expr {expr(join($l,"+"))} => 6 REFERENCE IMPLEMENTATION ========================== None currently COPYRIGHT =========== Copyright (c) 2012 by GriffinTk This document is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License []. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows