That article is from 2001, so about 7 years old, which is much in
computing... I posted a reply, pointing out that in 8.5 I'd do the
Fibonacci test like this:
% proc tcl::mathfunc::fib n {expr {$n<2? 1: fib($n-2)+fib($n-1)}}
% expr fib(5)
8
% expr fib(6)
13
% expr fib(7)
21
The way I read the article above was that the author objected to the
use of expr to perform arithmetic operations, and no amount of fancy
coding was going to convince him differently.
His Lua examples were pretty. Alas, what good is pretty if too few
people use the language?
Well, the language of expr is obviously not the same as Tcl, so a
dedicated command is the most orthogonal way. But you can hide even
that outer [expr] out of sight, if you so wish:
% proc fun {name argl body} {proc $name $argl [list expr $body]}
% fun tcl::mathfunc::fib n {$n<2? 1: fib($n-2)+fib($n-1)}
% expr fib(7)
21
why not also include the tcl::mathfunc:: into "fun"?
% proc fun {n a b} {proc tcl::mathfunc::$n $a [list expr $b]}
% fun fib n {$n<2 ? 1 : fib($n-2)+fib($n-1)}
% expr fib(7)
21
Yup... more fun! :^)
But there is a really valid point in the complaint, that I stumble
across sometimes. The use of expr for arithmetics makes code very
unreadable, if you want to call a function with some parameters. Let's
say I want to position a rectangle in the right half of a canvas, with
some margin:
set width blabla
set height blabla
set margin blabla
pack [canvas .c -with $width -height $height]
.c create rectangle [expr {$width/2+$margin}] $margin \
[expr {$width-$margin}] [expr {$height-$margin}]
This last statement looks rather ugly. In C and every language, where
the statements are expressions, you'd write
c->createRect(width/2-margin, margin, width-margin, height-margin);
Of course we could tune Tcl to have listexpr:
.c create rectangle {*}[listexpr {$width/2+$margin} $margin
{$width-$margin} {$height-$margin}]
(not done by me, just some imgaination) making it much better. But its
simply bad to have such a bulky standard syntax.
Christian
Where did you post the reply? I can't find it on
http://reddit.com/r/programming/info/68u11/comments/
Even back in 2001 it was trivial to define maths operators as commands,
or even to do some simple syntax sugar:
proc func {name params body} {
proc $name $params [string map {( "[expr {" ) "}]"} $body]
}
func fib n {
if {$n < 2} {
return 1
} else {
return ([fib ($n-1)] + [fib ($n-2)])
}
}
(Of course this only works in limited cases).
I don't know why the original article author thought this was a major
flaw of the language. I would quite like nicer syntax for expr too (I
love the look of the above fib definition), but I certainly wouldn't
abandon the language over it. A much more interesting discussion would
have been on the downsides of everything is a string, such as e.g. the
need for "--" end-of-option markers in some commands, or comparative
difficulty of static analysis. (Note, I'm not saying these are
significant problems).
-- Neil
I got a reply mail: "Your message to the moderated usenet group
comp.compilers has been
received. Within a few days, it should either be posted to usenet or,
if
for some reason it's not suitable for posting, returned to you."
Or, in 8.5, use the math ops as commands.
namespace path ::tcl::mathop
.c create rectangle [+ [/ $width 2] $margin] $margin \
[- $width $margin] [- $height $margin]
--
73 de ke9tv/2, Kevin
> Or, in 8.5, use the math ops as commands.
>
> namespace path ::tcl::mathop
>
> .c create rectangle [+ [/ $width 2] $margin] $margin \
> [- $width $margin] [- $height $margin]
Wow! Polish notation. :)
--
ZB
.c create rectangle $width/2+$margin $margin ...
should be valid and it could internally invoke [expr] on arguments
passed to it. Each command that accepts an integer as argument would
have to be modified to process such arguments but it would provide a
clean solution to this problem.
Hemang.
That is the reason why I created "xsource" (http://wiki.tcl.tk/20759)
With xsource you can write:
.c create rectangle $witdh/2-$margin $margin $width-$margin $height-
$margin
And this is automatically translated to:
.c create rectangle [expr {$witdh/2-$margin}] $margin [expr {$width-
$margin}] [expr {$height-$margin}]
This is the benefit, but of course, there are drawbacks to this
approach,
mainly the fact that it makes the syntax rules more complex.
Hope it helps
Stéphane
This is related to TIP 273 which suggested doing this whereever a
numeric value was required. It was rejected as calling expr introduces
double-substitution into all of these places, which can cause incorrect
behaviour and is a security risk. For instance, if your $width variable
came from user input or some untrusted source then it could well cause
problems (e.g. if someone enters "[file delete -force ~/]"). The only
safe way to handle this would be to require braces around all such
arguments:
.c create rectangle {$width/2+$margin} {$margin}
But this is an incompatible change and quite ugly. Altering the syntax
of Tcl (e.g. as in the xsource example) is one approach that is safer as
it can surround the word with braces before Tcl has substituted it, but
it can still run into potential incompatibilities.
-- Neil
math {
.c create rectangle $width/2+$margin $margin \
$width-$margin $height-$margin
}
without the ugly expr-ing, bracing []-ing. Though I'm confident one can
write proc math{} in Tcl, the efficiency would be probably quite bad.
Christian
Probably not. If you used something that transformed your code into
some proc that gets called instead (with proper uplevel etc.) your
only paying once, when the code is created, some kind of preprocessor,
like sugar macros.
Michael
Cheap hack version:
proc math body {
uplevel 1 [string map {( "[expr {" ) "}]"} $body]
}
math {
.c create rectangle ($width/2+$margin) $margin \
($width-$margin) ($height-$margin)
}
Change the delimiters if you are worried about arrays etc.
-- Neil
One way would be to use (( and )) as the delimiters, as they're a lot
rarer in Tcl scripts. I suppose could also use some of the more exotic
«quotes» or 【brackets】 in 〔unicode〕, but they're often harder for
people to type.
Donal.
No, there's really not a valid point in assuming that languages should
understand elementary arithmetic in their syntax, as opposed to some
other domain of operation (like strings or vectors or matrices), or
even that syntax should be purely a control construct.
Simply because most languages support arithmetic as part of their
syntax and balk at the idea of + for string concatenation or >> for
streams doesn't make them right, it just makes them prejudiced ...
usually at the expense of efficient representation. Other languages
invent weird and non-obvious operators, or allow operator overloading
(and everyone has their own opinion on that).
Maths is not a strong point for Tcl - performance wise you wouldn't
select Tcl if you expected to perform a lot of calculations - so it
doesn't make sense to give arithmetic some special privilege like
inclusion in the parser.
Polish notation is supported in 8.5 (e.g. [/ $width 2] ) and neatly
deals with most of the verbosity complains that target expr{}.
Regards,
Twylite
It is not "out of the box", though.
One first needs to import stuff from tcl::mathop (and/or tcl::mathfunc).
namespace import ::tcl::mathop::*
PS: by explicitly defining such-named procedures, polish notation
was even previously possible, but only with even more hassle.
> No, there's really not a valid point in assuming that languages should
> understand elementary arithmetic in their syntax, as opposed to some
> other domain of operation (like strings or vectors or matrices), or
> even that syntax should be purely a control construct.
On the other hand, many developers prefer a programming language that
accomodates their desires and preferences, rather than use a language
which forces them to do things that make them work harder.
The fact that expr is something that's been a source of complaints for
probably a dozen years or more seems to me to indicate that dislike of
it isn't a fad.
Some may expect that it is tcl features like this that cause it to be
unpopular. I would disagree, however. If I saw people submitting Tcl
Improvement Proposals regularly that were being rejected without
discussion, then perhaps I might consider there to be merit. What
tends to be the case, in my experience, is that either a) no one
bothers to write up the TIP, b) someone does write up a TIP, there is
an initial bit of discussion and then silence for years, c) someone
writes up a TIP, there is discussion, with either alternatives
suggested or general problems with the entire idea, and eventually the
TIP is rejected, d) someone who REALLY has a need/interest/problem
works with the TCT and others to see that the new proposal makes it
into the core.
Of the four alternatives that I generally see, c is probably the least
common, followed by d, then b, and finally a. Complaints about Tcl
generally are not accompanied by attempts to discuss and resolve the
problems - just used as "target practice" by those who don't want to
bother with the language.
Andreas Leitgeb wrote:
> Twylite <twylit...@gmail.com> wrote:
> > Polish notation is supported in 8.5 (e.g. [/ $width 2] ) and neatly
> > deals with most of the verbosity complains that target expr{}.
>
> It is not "out of the box", though.
> One first needs to import stuff from tcl::mathop (and/or tcl::mathfunc).
>
> namespace import ::tcl::mathop::*
Thats a bogus argument basically. In other languages you need to do
the same or similar things all over the place, e.g. #include <stdio.h>
in C or import operators in python.
Keeping the global namespace clean is a good thing in general and the
namespace import might add to some boilerplate right below you
'package requires' but thats it...
And if you don't agree, just build your own init.tcl that does the
namespace import for you and customize your installation...
Michael
I'm curious -- has it really be a "source of complaints" or just a
sticking point for nay-sayers? Do professional tcl programmers (or
professional programmers in general) complain about this? To me it's a
complete no-op, but then I'm known to have a weird sense of what's good
when it comes to programming languages.
Even if it's just the nay-sayers that complain, that doesn't make the
complaint any less valid. I'm just curious if a significant number of
people who actually use the language see it as a problem.
Count me as one that doesn't see it as a practical problem, but will
concede that perhaps it is a marketing problem.
--
Bryan Oakley
http://www.tclscripting.com
[snip]
> Even if it's just the nay-sayers that complain, that doesn't make the
> complaint any less valid. I'm just curious if a significant number of
> people who actually use the language see it as a problem.
[snip]
Let's consider this expression written in algebraic notation, where F is
a proc:
5 * F(x-2,x+3)
This translates to Tcl as:
expr {5 * [F [expr {$x-2}] [expr {x+3}]]}
which is quite bad, for my taste.
Personally, if the new mathops allows me to write
[* 5 [F [- $x 2] [+ $x 3]]]
I'm happy, because I love Lisp, but most people out there hates it, so
I'm not sure if this is a big improvement for the acceptance of Tcl.
--
Oscar
more new syntax!!!
.c create rectangle {#}$width/2+$margin $margin \
{#}$width-$margin {#}$height-$margin
> Let's consider this expression written in algebraic notation, where F is
> a proc:
>
> 5 * F(x-2,x+3)
>
> This translates to Tcl as:
>
> expr {5 * [F [expr {$x-2}] [expr {x+3}]]}
>
> which is quite bad, for my taste.
Agreed. But if you can put F into the tcl::mathfunc namespace, it
becomes
expr {5 * F($x-2,$x+3)}
which suddenly looks much better... :^)
(One main advantage of tcl::mathfunc, in my eyes, is that it allows to
remain in the [expr] language, and avoid the ugly embedded calls to
[expr].)
> Keeping the global namespace clean is a good thing in general and the
> namespace import might add to some boilerplate right below you
> 'package requires' but thats it...
My posting wasn't primarily intended as a rant about the extra
boilerplate, but rather to prevent confusion about Twylight's
"is supported in 8.5". He appeared to imply that in Tcl 8.5,
+,-,*,/ would be standard commands immediately available, the
latter of which I felt like correcting.
>> expr {5 * [F [expr {$x-2}] [expr {x+3}]]}
>>
>> which is quite bad, for my taste.
>
> Agreed. But if you can put F into the tcl::mathfunc namespace, it
> becomes
> expr {5 * F($x-2,$x+3)}
> which suddenly looks much better... :^)
Yes, it is much better, but it is unworthy to put into tcl::mathfunc
namespace lots of functions just because they accept and return
numbers. Not to mention all those functions that come from elsewhare (a
library, extension, etc).
[snip]
--
Oscar
% proc libfunc {a} {expr {$a*2}}
% expr {libfunc(4)}
invalid command name "tcl::mathfunc::libfunc"
% interp alias {} tcl::mathfunc::libfunc {} libfunc
% expr {libfunc(4)}
8
Mark
>
> [snip]
>
> --
> Oscar
% proc libfunc {a} {expr {$a*2}}
expr {libfunc(4)}
invalid command name "tcl::mathfunc::libfunc"
>> Yes, it is much better, but it is unworthy to put into tcl::mathfunc
>> namespace lots of functions just because they accept and return
>> numbers. Not to mention all those functions that come from elsewhare (a
>> library, extension, etc).
>
> % proc libfunc {a} {expr {$a*2}}
> expr {libfunc(4)}
> invalid command name "tcl::mathfunc::libfunc"
> interp alias {} tcl::mathfunc::libfunc {} libfunc
> % expr {libfunc(4)}
> 8
And your point is... ?
--
Oscar
That library functions are not a problem to use. I thought you were
refering to the fact you couldn't put them in tcl::mathfunc. Looks
like I was mistaken.
Mark
>> > % proc libfunc {a} {expr {$a*2}}
>> > expr {libfunc(4)}
>> > invalid command name "tcl::mathfunc::libfunc"
>> > interp alias {} tcl::mathfunc::libfunc {} libfunc
>> > % expr {libfunc(4)}
>> > 8
>>
>> And your point is... ?
>
> That library functions are not a problem to use. I thought you were
> refering to the fact you couldn't put them in tcl::mathfunc. Looks
> like I was mistaken.
Yes. The ugly part is to inject all those functions on the namespace.
--
Oscar
Óscar Fuentes wrote:
> Yes. The ugly part is to inject all those functions on the namespace.
The intent is not for you to place commands in the ::tcl::mathfunc
namespace. The intent is for you to put commands in the tcl::mathfunc
namespace *relative* to the namespace of your code.
namespace eval my {
proc tcl::mathfunc fib {n} {...}
# Now in all expressions in code in ::my you are free to use the
# fib(.) function. There is no interference with the built-in
# function commands over in ::tcl::mathfunc, nor those function
# commands supporting another module over in ::his::tcl::mathfunc
}
--
| Don Porter Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|
>>>>> % proc libfunc {a} {expr {$a*2}}
>>>>> expr {libfunc(4)}
>>>>> invalid command name "tcl::mathfunc::libfunc"
>>>>> interp alias {} tcl::mathfunc::libfunc {} libfunc
>>>>> % expr {libfunc(4)}
>>>>> 8
>
>> Yes. The ugly part is to inject all those functions on the namespace.
>
> The intent is not for you to place commands in the ::tcl::mathfunc
> namespace. The intent is for you to put commands in the tcl::mathfunc
> namespace *relative* to the namespace of your code.
>
> namespace eval my {
> proc tcl::mathfunc fib {n} {...}
>
> # Now in all expressions in code in ::my you are free to use the
> # fib(.) function. There is no interference with the built-in
> # function commands over in ::tcl::mathfunc, nor those function
> # commands supporting another module over in ::his::tcl::mathfunc
> }
Seems that I'm missing something here, so I'll ask: let's suppose that I
have some large chunk of source code (tcllib, for example) and I want to
take advantage from the syntax introduced by tcl::mathfunc.
My undestanding is that I must inject all those function names,
explicitly and one by one, in tcl::mathfunc. Is this correct?
--
Oscar
Yes. You can automate it easily enough, using [info commands].
-- Neil
Yes. You can automate it easily enough either using [info commands] or
using existing namespace features:
namespace eval tcl::mathfunc { namespace import ::otherns::* }
-- Neil
>> Seems that I'm missing something here, so I'll ask: let's suppose that I
>> have some large chunk of source code (tcllib, for example) and I want to
>> take advantage from the syntax introduced by tcl::mathfunc.
>>
>> My undestanding is that I must inject all those function names,
>> explicitly and one by one, in tcl::mathfunc. Is this correct?
>
> Yes. You can automate it easily enough either using [info commands] or
> using existing namespace features:
>
> namespace eval tcl::mathfunc { namespace import ::otherns::* }
Thanks, Neil. So there is an automated or one-liner method for putting
lots of functions into a namespace and take advantage of the
expr/tcl::mathfunc combo. Nice.
--
Oscar