Tcl Math Syntax is Inferior to JavaScript/Python/Ruby/C/C++/Java/Perl/PHP

Problem

Tcl's mathematical expression & assignment syntax is unnecessarily verbose and thus inferior to many other programming languages (especially Ruby, JavaScript & Python). Every extra redundant character means:

  • Potential typos/errors
  • More information that needs to be read and processed by both people and computers
  • More information that needs to be typed
  • Tarnishing Tcl's clean, simple and beautiful space delimited syntax

Proposed Solution

Add more standard operators to tcl::mathop in Tcl 8.6, such as:

	=
	+= -= *= /= %= **=
	&= |= ^=
	<<= >>=
	++ --

And add the function pi() to tcl::mathfunc.

Quick and dirty hack implementation for demonstration purposes:

	proc = {var args} {
		upvar 1 $var uvar
		set uvar [expr $args]
	}

	proc += {var args} {
		upvar 1 $var uvar
		set uvar [expr $uvar + ($args)]
	}

	proc ++ var {
		upvar 1 $var uvar
		incr uvar
	}

Examples/Comparisons of Clarity & Line Lengths

Assign Result of Single Operator Expression

	s = 60 * 60 * 24			# JavaScript, Python, Ruby
	$s = 60 * 60 * 24;			# Perl, PHP
	int s = 60 * 60 * 24;			# C, C++, Java
	set s [expr 60 * 60 * 24]		# Tcl
	set s [* 60 60 24]			# Tcl 8.5
	= s 60 * 60 * 24			# Proposed Tcl 8.6

Assign Result of Multiple Operator Expression (Long Version)

	y = m * x + b				# JavaScript, Python, Ruby
	$y = $m * $x + $b;			# Perl, PHP
	float y = m * x + b;			# C, C++, Java
	set y [expr $m * $x + $b]		# Tcl
	= y $m * $x + $b			# Proposed Tcl 8.6
	= y m * x + b				# Future Fantasy Tcl: lookup
						# unrecognized tokens as variables/procedures

Assign Result of Multiple Operator Expression (Short Version)

	y=m*x+b					# JavaScript, Python, Ruby
	$y=$m*$x+$b;				# Perl, PHP
	float y=m*x+b;				# C, C++, Java
	set y [expr $m*$x+$b]			# Tcl
	= y $m*$x+$b				# Proposed Tcl 8.6
	= y m*x+b				# Future Fantasy Tcl: lookup
						# unrecognized tokens as variables/procedures

Assign Result of Mixed Expression

	$x = sin( pi() / 2 );			# PHP
	x = Math.sin Math::PI / 2		# Ruby
	x = Math.sin( Math.PI / 2 )		# JavaScript
	x = math.sin( math.pi / 2 )		# Python
	double x = Math.sin( Math.PI / 2 );	# Java

	const double PI = acos( -1 ); 		# C, C++: do it yourself Pi
	double x = sin( PI / 2 );

	use constant PI => atan2( 1, 1 ) * 4;   # Perl: do it yourself Pi
	$x = sin( PI / 2 );

	proc pi {} [list return [expr acos(-1)]];  # Tcl: do it yourself Pi
	set x [expr sin( [pi] / 2 )]

	= x sin( pi() / 2 )			# Proposed Tcl 8.6
	= x sin pi / 2				# Future Fantasy Tcl: optional parenthesis

Accumulate/Addition

	s += 60					# JavaScript, Python, Ruby
	s += 60;				# C, C++, Java
	$s += 60;				# Perl, PHP
	incr s 60				# Tcl
	+= s 60					# Proposed Tcl 8.6

Scale/Multiplication

	x *= 2					# JavaScript, Python, Ruby
	x *= 2;					# C, C++, Java
	$x *= 2;				# Perl, PHP
	set x [expr {$x * 2}]			# Tcl
	*= x 2					# Proposed Tcl 8.6

Increment

	++x					# JavaScript
	++x;					# C, C++, Java
	++$x;					# Perl, PHP
	x += 1					# Python, Ruby
	incr x  				# Tcl
	++ x					# Proposed Tcl 8.6

Post Script

If this has been previously recommended/discussed then could someone provide a link?

I know this wiki may not be the ideal place to propose this, but it is the quickest.


NEM See e.g. let and expr shorthand for Tcl9. The proposed = command will be non-optimal as shown. See Brace your expr-essions for reasons why. The same applies to the other assignment short-cuts, which is probably why they were not added. See also http://tip.tcl.tk/ for various relevant TIPs along with rationale discussions. A pi() function is a simple addition. Such requests can either be TIPed or added as Feature Requests to the Tcl project tracker at http://sourceforge.net/projects/tcl .

techmisc 2008-07-02

Re: Links: The expr shorthand link has a good discussion, but unfortunately concentrates mainly on expr and overlooks the set and expr combination. The combination is important because even if you were to only change Tcl's syntax/grammar and dedicate symbols to replace expr (eg. backticks), you would still need to use set which makes code unnecessarily verbose/lengthy. Compare Tcl with and without assignment (ie. combined set & expr) operators:

	# Tcl
	for {set i 1} {$i <= 1024} {set i [expr {$i * 2}]} { myfunc $i }
	for {set i 0} {$i <= 10} {incr i} { myfunc [expr {2 ** $i}] }

	# Tcl (backticks for expr)
	for {set i 1} {$i <= 1024} {set i `$i * 2`} { myfunc $i }
	for {set i 0} {$i <= 10} {incr i} { myfunc `2 ** $i` }

	# Tcl (assignment operators)
	for {= i 1} {$i <= 1024} {*= i 2} { myfunc $i }
	for {= i 0} {$i <= 10} {++ i} { myfunc [expr {2 ** $i}] }

	# Tcl (backticks for expr & assignment operators)
	for {= i 0} {$i <= 10} {++ i} { myfunc `2 ** $i` }

	// JavaScript
	for (i = 1; i <= 1024; i *= 2) myfunc( i )
	for (i = 0; i <= 10; i++) myfunc( Math.pow( 2, i ) )

Re: "Non-optimal" code: That's why it's qualified as "quick and dirty", "hack" and "demonstration". :-)

Thanks for the info on expr-ession execution. But since they run many (eg. 10!) times faster just by passing 1 argument instead of N arguments, then maybe expr or Tcl's parser could be improved.

And I won't be adding a TIP because I'm a Tcl newbie. Hopefully someone else will pick up these ideas and run with them. I declare all content I have submitted Public Domain.


Sarnold See xsource for an attempt to solve this problem.

Lars H: And infix for yet another approach.

techmisc 2008-07-02 Thanks for the links.


ZB 30.06.2008. So, "duplicated syntax"? Both "++ x" and "incr x"? But what for? Those, who are accepting TCL's syntax, won't need it. For those, who feel uncomfortable with TCL's syntax, it's too limited change to be persuaded: "now you'll like TCL". So again: what for? I would to quote something from the main page: "Tcl is a simple-to-learn yet very powerful language. Its syntax is described in just a dozen rules". Not enough rules - let's add some more?

Perhaps it could be much better to switch to "project L" syntax change proposals completely instead? Just to keep consistency.

techmisc 2008-07-02

Tcl already has duplicated syntax:

	set x [expr {$x + 1}]
	incr x

	set x [expr {pow( 2, 3 )} ]
	set x [expr {2 ** 3} ]

What's important is the duplicated syntax doesn't break Tcl's "command arg arg..." prefix style grammar/syntax. Neither do "= y $x", "+= s 60" or "++ x".

And they are industry standard operators.

If that's a problem, consider them C operators, which is where all the other languages got them.

If that's still a problem, consider the syntax of the expr command is different to Tcl syntax. It probably came from C. Tcl is written in C, and it's almost certain operators just like the ones proposed are used.

Also, the fact that there are so many other proposed solutions to expr & assignment syntax shows Tcl programmers believe there's room for improvement.

You can still use "set x expr {$x + 1}". But you can also use "++ x" or "+= x 1" because they're shorter, simpler and clearer.


WJG (01/07/08) Personally I find that whilst the alternative symbols for keywords such as incr and set might make Tcl 'look more familiar' they are not necessary. In fact, I suspect that the replacing 'incr s' with '+= s' will cause as many key board entry errors. Indeed, my overall comment on such introspection would be that if a coder needs python or something else, then use it, Saying that Tcl needs to me more like python, perl or c++ is just an argument against using Tcl rather than urging the introduction of symbol synonyms. Extensibility, as I understand it implies a simple core Tcl with flexibility entering through the development project led extensions. With so many packages now becoming shipped with Tcl, a 'batteries included' version of Tcl is becoming bloatware. The more that is added, the more there is to dislike. Surely, there will be a point when potential users, unable distinguish what is core and add-on will find it all too confusing and therefore pursue an alternative. I myself went through a period of introspection a while ago and seriously thought of swapping from Tcl to something else, such as Lua or Python using wxWidgets. But I came back to Tcl, not for anything new that has come along, but because the original idea was both simple and clean. The command syntax, in keeping the flavour of shell scripting is robust. Perhaps the emergence of eclectic collections of packages and extensions is because Tcl is now being 'designed by committee' rather than the outcome and the vision of its original creator.

techmisc 2008-07-02

Re: Familiarity & Other languages: This proposal isn't about other languages. They were listed to demonstrate how Tcl can be improved by adding standard mathematical operators which would reduce character bloat.

Re: Not necessary: Neither is incr, you can always "set x expr {$x + 1}". Neither are multiple loop control structures (for, foreach, while). Neither are multiple branching control structures (if, switch). But Tcl has them all because they make code simpler and cleaner.

Re: Will cause typing errors: Actually the exact opposite. Compare:

	set x [expr {$x * 2}]					# 21 keystrokes
	*= x 2							# 6 keystrokes

Statistically you'll make more typos in Tcl as it is. And that's with short variable names. What about more meaningful names, which you have to repeat twice?

	set well_named_var [expr {$well_named_var * 2}]		# 47 keystrokes
	*= well_named_var 2					# 19 keystrokes

Re: Extensibility: The operators were proposed for the tcl::mathop namespace so they won't bloat Tcl's core commands.

Re: Confusion: Any library feature you don't want to use can be ignored. But by including them in Tcl they will be a standard as opposed to each programmer reinventing the wheel.

Additionally Tcl is confusing as is, for example there are two power commands/operators: pow and **. To decrement a value, you have to increment it (!) by a negative number (ie. there's a incr command, but no decr command).

Re: Simple and Clean: Look at all the examples; the new operators will make Tcl cleaner by promoting space delimited syntax rather than having to include "set", "expr", "", "", "{" and "}" in statements.


DKF: We've been considering doing assignment operators. The problem was (IIRC) that it introduces a new syntactic class in our expression parser (approximately "lvalue") and that makes it tricky in a number of ways. Once that's done, doing a bunch of infix assignment operators is easy enough.

You can do pi() for yourself right now. It's a one-line script!

 proc ::tcl::mathfunc::pi {} {expr {double(3.14159265)}}
 # I got the value from Google so it must be right!

Lars H: Why not take advantage of Tcl's status as dynamic language to construct the procedure body automatically?

 proc ::tcl::mathfunc::pi {} [list return [expr acos(-1)]]

In 8.5 this returns 3.141592653589793 for me, and all those digits are correct.

techmisc 2008-07-02

Re: Lars H: Why not...: efficiency. Pi isn't going to change, hard coding it is OK. Unless someone wants to use Tcl's pi() to calculate the Nth digit... Lars H: Exactly, pi isn't going to change! DKF's version feeds the value through double every time it is called, mine just returns a cached value that was computed when the procedure was created. Though it occurs to me now that interp alias {} tcl::mathfunc::pi {} return -level 0 [expr acos(-1)] is probably better still.

Re: DKF: Pi: Thanks for namespace tip, but I have no idea why it's not standard already... does Tcl have something against circles? ;-)

Re: Syntactic Class: I don't know how Tcl's code is architectured, but since Tcl already has the very similar procedure incr built into the code, implementing the proposed operators should be (in theory) almost identical. Unless you're planning on implementing them as infix operators, but that would break Tcl's simple syntax. Not to mention potential rebellion by Tcl programmers against changing the existing grammar/syntax...

But if infix operators are planned for Tcl then please allow user definable infix operators/procedures. Allowing only hardcoded infix operators wouldn't be very Tclish.

DGP The parser is not set up to support an extensible set of operators, or grammar or precedence rules for them, since that's what you seem to be looking for. Any proposal to do that would need careful review to check that whatever flexibility benefits are gained aren't more than paid for in performance losses. For now, the path for people who want to work with an extended set of operators is to define their own [::my::expr] command that does what they want.

techmisc It was a misunderstanding on my part. I thought Tcl's prefix syntax (proc arg arg arg) was being extended to include hardcoded infix operators (var = value), and so why not allow user definable infix "operators" (by which I meant procedures) to Tcl itself (eg. arg user_proc arg arg). All this because I thought "our expression parser" meant Tcl's parser, rather than expr's parser. Hence the comments about breaking the simple syntax, rebellion etc.

In turn, my comment was misunderstood as "allow user defined infix operators in expr", which I wasn't suggesting at all, but may be a good idea. For example, it could allow advanced math (complex numbers, matrix math) but as you pointed out there would be costs, some potentially significant and not obvious.

What Tcl programmers want (see various linked pages for some proof) is an overall better method for assignments (eg. =), expressions (no idea, backticks?), and both (eg. += *=). Thus the assignment procedures in mathop suggestion, and comparison with other languages above. Tcl's developers will probably have better (read: more efficient) ideas, and it seems one of them is to put assignment operators in expr. This is a positive step but doesn't solve the verbosity problem:

	set x [expr {$x * 2}]			# Current math assignment via Tcl syntax
	expr { [set x [expr {$x * 2}] }		# Current math assignment via expr

	expr { $x *= 2 }			# Tcl's developers infix assignment operator
						# Better than both of the above, but:

	*= x 2					# Ideal: Shortest, and space delimited
	*= x {2}				# Ideal with compromise

Hopefully expr's new assignment operators will be matched with new assignment procedures in mathop, just like with + - * / etc. And hopefully the syntax precedent set by "if" and "while" of using expressions without expr {} will support the idea (see comment below for details).

DKF: I wasn't interested in doing the most efficient version, I was just showing off that it could be done. There's no pi() right now because it's trivial to hard code. (It'd be better if expr understood π to be that constant directly, of course…)

The syntactic class comment was exactly that we're looking at doing infix assignment operators for expressions. (Non-expression syntax will stay the same as now.) I don't know if we'll end up using = or := (or something from the unicode zoo) for assignment; I'm not too worried over that detail for now.

And we currently only allow a fixed set of operators with fixed semantics. Changing that is tricky, and has some really nasty consequences (see the C++ standard library for many examples of misuse). OTOH, some functional languages (SML that I know of) allow the definition of extra operators without coming apart at the seams; mind you, most of their practitioners know better than to violate the type assumptions implicit in mathematical operations.

techmisc

Re: Syntactic Class: I see. I thought you meant introducing infix into statements eg. "my_var = 1" and I was arguing for "my_var my_proc 1" (as opposed to the current "my_proc my_var 1"). I think user defined operators in expr are of less importance because expr implies mathematics, not general purpose use. Unless you want to write a complex number operator, I guess. But I wouldn't worry too much about the consequences of giving power to Tcl programmers, they can already do anything thanks to the power of everything is a string.

In the spirit of matching the functionality of expr with procedures in mathop (ie. "expr {1 + 1}" to "+ 1 1"), I'm hoping any new assignment operators in expr will have mathop equivalents, meaning a minimum functionality of:

	expr {$s = 0}			->	= s 0
	expr {$s += 60}			->	+= s 60
	expr {$x *= 2}			->	*= x 2

	expr {$s = 60 * 60 * 24}	->	= s [expr {60 * 60 * 24}]
	expr {$y = $m * $x + $b}	->	= y [expr {$m * $x + $b}]
	expr {$x = sin( pi() / 2 )}	->	= x [expr {sin( pi() / 2 )}]

And if you consider the mathop assignment procedures to be of the same style as "if" and "while" then hopefully they can have an implied "expr" as their second argument:

	= s {60 * 60 * 24}
	= y {$m * $x + $b}
	= x {sin( pi() / 2 )}

Not quite as brief as they could be, but far better than:

	set x [expr {sin( pi() / 2 )}]

Hopefully increment and decrement operators will be available too:

	for {= i 1} {$i <= 10} {++ i} {}
	for {= i 10} {$i >= 1} {-- i} {}

Unfortunately passing results of expressions to procedures will still be verbose:

	myfunc x / y			# Ruby
	myfunc( x / y )			# JavaScript, Python
	myfunc( $x / $y );		# Perl, PHP
	myfunc( x / y );		# C, C++, Java
	myfunc [expr {$x / $y}]		# Tcl

I have no idea how to fix that without introducing new syntax (eg. backticks for expr):

	myfunc `$x / $y`		# Fantasy Tcl

Since backticks are shell features, and Tcl is shellish, this might be acceptable. If they were introduced, it would also allow the commands:

	`$s = 60 * 60 * 24`
	`$y = $m * $x + $b`
	`$x = sin( pi() / 2 )`
	`$s += 60`
	`$x *= 2`
	`++$x`

Re: "=" vs ":=" vs other: I would bet most programmers would prefer "=" because it's become standard. A bonus is typing "=" is at least twice as fast as ":=" (you have to shift ";" to get ":" on English keyboards). It also leaves ":" free for other uses. And obviously ISO-8859-1 over Unicode, think of the vi(m) users!

ZB ":=" for assignment is always better than single "=" just because it cannot be confused with "equal to". "Less typing" is not superior to "more clear and obvious".

techmisc Re: Confusion: I thought the confusion was due to overloading "=" for both assignment and equality, as BASIC does. Since Tcl's expr (and every other mainstream language) uses "==" for equality there's no problem using "=" for assignment (as all mainstream languages do). It also allows a symmetry between assignment operators and expressions ie. the operator in front of the "=" is used in the expr-ession:

	Concise		Verbose
	--------------------------------------
	+= x 2		set x [expr {$x + 2}]
	-= x 2		set x [expr {$x - 2}]
	*= x 2		set x [expr {$x * 2}]
	/= x 2		set x [expr {$x / 2}]
	**= x 2		set x [expr {$x ** 2}]
	<<= x 2		set x [expr {$x << 2}]

So ":=" means:

	:= x 2		set x [expr {$x : 2}]

What's the operator ":" do? Ignore it's left and return it's right? Kind of useless, so you have to think of ":=" as pure assignment:

	:= x 2		set x [expr {2}]

Which by itself is OK, but breaks the symmetry shown above. "=" doesn't have this problem because it doesn't have an operator in front of it, so the symmetry above is untouched by:

	= x 2		set x [expr {2}]

Re: "Clear and Obvious" > "Less Typing": I 100% agree. So what's more clear and obvious?

All industry programmers use "=", even those of non-C descent (BASIC/VB/ASP). I think even COBOL added "=" Mathematicians and the Sciences use "=": y = mx + b, E = mc2 Spreadsheets use "=": =A1+1 Word processors use it (!), in Word type: =rand() then enter Browsers (Cookies, HTTP) use "=": expires=2008, ?query=tcl&num=100 CGI uses "=": SCRIPT_NAME=script.tcl Shell uses "=": set VAR=123

Based on usage "=" is clear and obvious to everyone. I don't think ":=" is used significantly anywhere (Pascal? Eiffel?), and even if it is (Delphi?), it's nowhere near as clear and obvious as "=". Tcl's heritage is BSD/Shell/C, why buck the trend without good reason?

Besides, "=" is quicker to type. There's a whole key dedicated to it! :-)


techmisc 2008-07-02 Thanks to whoever added markup to the original message. I also fixed some bugs and added a Scale/Multiplication example alongside Addition.

DKF: You're welcome.

techmisc If it's possible to rename the page to "Math Syntax", that would be great. I didn't realize people would have to type "Tcl Math Syntax is Inferior to JavaScript/Python/Ruby/C/C++/Java/Perl/PHP" everytime they wanted to link here.

Lars H: The closest thing to renaming in this wiki is to create a new page and move all the content there. Math syntax probably wouldn't be a good name though, as it suggests the page describes existing behaviour, rather than a discussion of what could come. Math syntax suggestion (techmisc) is probably suitably specific. You could also focus on your initial contribution, which is arguably a useful comparison of math syntaxes for several scripting languages.

techmisc Looks like it stays as is.


slebetman: Changed the Tcl do-it-yourself PI to be more in spirit like the Perl implementation.

techmisc I implemented it as a proc instead of a var because Pi is a constant that shouldn't be changed (eg. accidently). There's a discussion on how to implement it best including performance issues and making it available as a function in expr. Search for "3.14" on the page.