AMB

Alex Baker

I got into Tcl during my Master's degree while working with OpenSees, and I grew to love it :)

Projects:

  • Tin: A Github-based package manager for Tcl.
  • ndlist: A pure Tcl implementation of arbitrary rank tensors.
  • exprstar: Expr, but returns a list, with elements delineated by commas.

Better Math

I am very passionate about making math easier in Tcl, as I see it as one of the main reasons for Tcl's low popularity. The fact that we have to call "[expr {$a + $b}]" is ridiculous. In comparison, say, in Python (or any other programming language geared towards scientific computing), you just do "a + b". The sheer number of extra keystrokes required to do math in Tcl clutters any code that has a modest amount of calculations.

See my extensive discussions on the following pages:

This list below represents the current state of a dialogue between me and FM (and others) about Tcl math.

Proposals

1. Shorthand Notation:

If the first character in a Tcl command is an open parentheses, it signifies an expression, and will look for the matching close parentheses. The string contained in the parentheses will be parsed as a Tcl expression, exactly as if it was passed to the expr command. Newlines are allowed within the expression with no special meaning except whitespace. If there are any characters after the close parentheses (i.e. another word parsed by Tcl), it will throw an error.

Example:

set x 5.0
set y [($x*2)]; # 10.0
eval {
($x + $y
)   }; # 15.0
lmap value {1 2 3} {($value + 2)}; # 3 4 5
($x + 1) foo; # error, word encountered after expression

This shorthand notation is a modification of FM's concept, kudos to them for this idea.

Compatibility issues

If a procedure name starts with an open parentheses, it must be called by wrapping the name in braces (or quotes, or any other indirect method of calling a procedure).

proc (mycommand) {args} {puts "hello world"}
(mycommand); # invalid bareword "mycommand"
{(mycommand)}; # hello world

2. Native list notation

Multiple values can be returned from an expression or subexpression (in parentheses), exactly how arguments are parsed for math functions.

set x 5
expr {$x+1,$x*2,$x-3}; # 6 10 2

If there is no comma, it will not return a list of values, but just the value itself.

set x {hello world}
expr {$x}; # hello world
expr {$x,"foobar"}; # {hello world} foobar

For singleton lists, I propose that the mathfunc "l" be added, defined as follows:

proc ::tcl::mathfunc::l {args} {return $args}
set x {hello world}
expr {l($x)}; # {hello world}
expr {l($x,"foobar")}; # {hello world} foobar

Compatibility issues

None. Commas in expressions currently return an error, and the original behavior is unaffected.

3. Argument Expansion in Expressions

Let the * represent argument expansion within parentheses, exactly like the {*} expansion operator in normal Tcl evaluation.

set vec {1 2 3}
expr {max(*$vec)}; # 3

Combined with proposal 2, this allows for easy list concatenation.

set x 5
set vec {1 2 3}
set vec [expr {*$vec,$x-1,$x,$x+1}]; # 1 2 3 4 5 6
# lappend vec [expr {$x-1}] $x [expr {$x+1}]; # same as above.

Compatibility issues

None. The multiplication * operator is a binary operator in Tcl, so prepending it to an argument in an argument list currently returns an error.

4. Variable assignment:

If an expression has the syntax var = ..., where var can be a bare word, it signifies variable assignment. Example:

expr {x = 5.0}; # 5.0
expr {y = $x*2}; # 10.0
expr {2*(z = $x + $y)}; # 30.0

Compatibility issues

None. See https://core.tcl-lang.org/tips/doc/trunk/tip/282.md

5. Multiple expressions

Within an expression, multiple statements can be written, separated by semicolons. The last statement is what is returned. Combined with proposal #4, the following can be written:

Example:

expr {
   x = 5.0;
   y = $x*2;
   z = $x + $y
}; # 15.0
expr {z = ($x + $y;10.0)}; # 10.0

Compatibility issues

None. See https://core.tcl-lang.org/tips/doc/trunk/tip/282.md

6. ND-list index operator

Let the symbol @ represent an operator that performs the equivalent of "nget" and "nset" from my ndlist package, depending on whether it is followed by an assignment operator. This would first require that I implement ndlists into the Tcl core. This is very far off, but something I want to do eventually.

Access notation:

value @ indexlist

Assignment notation

varName @ indexlist = value

# Example (with shorthand notation)

set x {foo bar baz}
(x @ -1.0 = {hello world})
puts $x; # foo bar {hello world}
puts [($x @ (-1,1))]; # world

# Expanding a list:

set x {1 2 3}
# lset x end+1 10
# lappend x 10
(x = (*$x,10)); # Tcl expression equivalent

Compatibility issues

None. The @ symbol is not recognized by the expr engine.

7. Element-wise operations

Expressions in Tcl are strictly scalar. My package ndlist is a prototype for element-wise operations in Tcl, but it would be better if it was implemented in the core. Only numeric operators would be valid for ND-lists, as numeric ND-lists have non-ambiguous rank.

A simple approach would be to append the existing math operators with a period ".". This is how it is denoted in multiple other languages.

set x {1 2 3}
set y {{5 6}}
expr {$x + $y}; # {{6 7} {7 8} {8 9}}

It would allow for combining arrays that are compatible in dimension. As in, same dimension at each level, or unary. My ndlist package does also allow for combining arrays with dimensions like 1,6 and 4,3, because 6 is a multiple of 3, but in hindsight I think that this feature is too confusing.