TIP 408: Allow Any Command for expr Functions

EuroTcl/OpenACS 11 - 12 JULY 2024, VIENNA
Author:		Brian Griffin <[email protected]>
State:		Draft
Type:		Project
Vote:		Pending
Created:	17-Aug-2012
Tcl-Version:	9.1


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 [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 (c) 2012 by GriffinTk

This document is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License http://creativecommons.org/licenses/by-sa/3.0/deed.en_US .