Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A bit of tcl advocacy ...

453 views
Skip to first unread message

Rob Sciuk

unread,
Jun 17, 2012, 6:53:16 PM6/17/12
to

Ben Collver

unread,
Jun 17, 2012, 10:12:01 PM6/17/12
to r...@controlq.com
On Sunday, June 17, 2012 3:53:16 PM UTC-7, Rob Sciuk wrote:
> http://www.controlq.com/blog/wordpress/?p=381

This post compares programming TCL to jumping through flaming hoops.
https://groups.google.com/d/msg/comp.compilers/6yJBnXzntzQ/z3boS17QtugJ

The expr factorial example is also discussed in the following patch.
http://elf.org/etc/tcl-expr-patch.html

Gerald W. Lester

unread,
Jun 18, 2012, 12:44:12 AM6/18/12
to
And how often does one write such functions?

I'd guess about as often as one really writes "Hello World" examples -- a
case where Tcl/Tk shine.

--
+------------------------------------------------------------------------+
| Gerald W. Lester, President, KNG Consulting LLC |
| Email: Gerald...@kng-consulting.net |
+------------------------------------------------------------------------+

Christian Gollwitzer

unread,
Jun 18, 2012, 1:08:30 AM6/18/12
to
Am 18.06.12 04:12, schrieb Ben Collver:
> On Sunday, June 17, 2012 3:53:16 PM UTC-7, Rob Sciuk wrote:
>> http://www.controlq.com/blog/wordpress/?p=381
>
> This post compares programming TCL to jumping through flaming hoops.
> https://groups.google.com/d/msg/comp.compilers/6yJBnXzntzQ/z3boS17QtugJ

Yes, expr can be annoying sometimes. But note that in current Tcl
(8.5+), you can write:

proc tcl::mathfunc::fib n {
if {$n<2} { return 1 }
return [expr {fib($n-2)+fib($n-1)}]
}

which is much less obfuscated. In many cases, return is superfluous,
too, so you can simplify it even more:

proc tcl::mathfunc::fib n {
expr {$n<2 ? 1 : fib($n-2)+fib($n-1)}
}

and you get a shiny new fib() function inside expr. Also note, that it
is a particularly bad idea to compute Fibonacci numbers by recursion
instead of a loop or memoization.

Christian

Uwe Klein

unread,
Jun 18, 2012, 3:30:32 AM6/18/12
to
Certainly very deep philosophy ;-)

"
Access denied
user warning: Incorrect key file for table './elf115_elf/role.MYI'; try to repair it query: SELECT
p.perm FROM role r INNER JOIN permission p ON p.rid = r.rid WHERE r.rid IN (1) in
/usr/www/users/elf115/www.elf.org/html/modules/user/user.module on line 502.
user warning: Incorrect key file for table './elf115_elf/cache_content.MYI'; try to repair it query:
SELECT data, created, headers, expire, serialized FROM cache_content WHERE cid =
'content_type_info:en' in /usr/www/users/elf115/www.elf.org/html/includes/cache.inc on line 26.
<about 1000% more trash snipped>
"

now what programming language does spout that kind of gibberish?

uwe

Uwe Klein

unread,
Jun 18, 2012, 3:32:59 AM6/18/12
to
Christian Gollwitzer wrote:
> Also note, that it
> is a particularly bad idea to compute Fibonacci numbers by recursion
> instead of a loop or memoization.
>

But recursion is THE panacea of showing programming grogginess ;-=)

uwe

Donal K. Fellows

unread,
Jun 18, 2012, 4:07:41 AM6/18/12
to
On 18/06/2012 06:08, Christian Gollwitzer wrote:
> In many cases, return is superfluous, too, so you can simplify it even
> more:
>
> proc tcl::mathfunc::fib n {
> expr {$n<2 ? 1 : fib($n-2)+fib($n-1)}
> }
>
> and you get a shiny new fib() function inside expr. Also note, that it
> is a particularly bad idea to compute Fibonacci numbers by recursion
> instead of a loop or memoization.

Well, we can go even further:

proc function {name arguments body} {
uplevel 1 [list \
proc tcl::mathfunc::$name $arguments [list expr $body]]
}
function fib n {
$n<2 ? 1 : fib($n-2) + fib($n-1)
}

Of course, with the Fibonacci sequence you're better off using an
iterative calculation strategy anyway. But that's getting rather more
off-topic...

Donal.

Arjen Markus

unread,
Jun 18, 2012, 5:57:39 AM6/18/12
to
Op maandag 18 juni 2012 10:07:41 UTC+2 schreef Donal K. Fellows het volgende:
You might overcome the computational burden by using a memoizing technique.
The Wiki has an example of that - http://wiki.tcl.tk/10981 - and you do not
even need to change the original procedure. How is that for advocacy?

Regards,

Arjen

Kevin Kenny

unread,
Jun 18, 2012, 9:04:40 AM6/18/12
to
On 06/18/2012 04:07 AM, Donal K. Fellows wrote:
> Of course, with the Fibonacci sequence you're better off using an
> iterative calculation strategy anyway. But that's getting rather more
> off-topic...

And even farther off topic, you can do it in closed form. (Nearest
integers to the powers of phi.)

But of course, you've had a combinatorics course, so you knew that.

--
73 de ke9tv/2, Kevin

Kevin Walzer

unread,
Jun 18, 2012, 10:29:13 AM6/18/12
to
Meh. I find complaints like the "flaming hoops" one to be pointless. Tcl
isn't perfect, no language is, but its strengths--especially its
foundational inregration with Tk and ease of deployment of desktop apps
written in the language--overwhelm its weaknesses.

If you need more than Tcl offers, use another language. I do so with
Python, productively. Python's Tk bindings are quite good, and it offers
multiple deployment options. Python is a bit heavier than Tcl, more like
using a broadsword than a rapier, but it can certainly get the job done.

By way of comparison, I've also been circling around another language
that is currently Da Shizzle: Ruby. Very rich library ecosystem, better
than Python's and Tcl's in some respects, and good support for Tk. But
Ruby has almost no support for desktop app deployment if a) you are not
developing on Windows or b) not using MacRuby on the Mac, which is my
platform. Repeated queries on various mailing lists for some assistance
or guidance have been met with silence. This is a showstopper for me.
I'm not advanced enough in Ruby to roll my own solution. Both Python and
Tcl proved themselves to me in part because I could quickly cobble up a
"hello world" button dialog display, then wrap it as a standalone app.
Not so with Ruby.

Back to work after this entertaining tangent into a flamefest...

--
Kevin Walzer
Code by Kevin
http://www.codebykevin.com

Ben Collver

unread,
Jun 18, 2012, 1:00:28 PM6/18/12
to
On Sunday, June 17, 2012 9:44:12 PM UTC-7, Gerald W. Lester wrote:
> On 6/17/12 9:12 PM, Ben Collver wrote:
> > On Sunday, June 17, 2012 3:53:16 PM UTC-7, Rob Sciuk wrote:
> >> http://www.controlq.com/blog/wordpress/?p=381
> >
> > This post compares programming TCL to jumping through flaming hoops.
> > https://groups.google.com/d/msg/comp.compilers/6yJBnXzntzQ/z3boS17QtugJ
> >
> > The expr factorial example is also discussed in the following patch.
> > http://elf.org/etc/tcl-expr-patch.html
>
> And how often does one write such functions?
>
> I'd guess about as often as one really writes "Hello World" examples -- a
> case where Tcl/Tk shine.

Are recursive functions that uncommon?

Robert Heller

unread,
Jun 18, 2012, 2:01:27 PM6/18/12
to
No, just that for some functions, a non-recursive, iterative solution
exists and is faster.

>

--
Robert Heller -- 978-544-6933 / hel...@deepsoft.com
Deepwoods Software -- http://www.deepsoft.com/
() ascii ribbon campaign -- against html e-mail
/\ www.asciiribbon.org -- against proprietary attachments



Gerald W. Lester

unread,
Jun 18, 2012, 5:37:34 PM6/18/12
to
No, but for many numeric computations an iterative solution exist and is faster.

What I am attempting to say is that the example is contrived and, outside of
classes at a university, not one you would actually hit very often.

If you want a real world recursion example that occurs fairly frequently,
then do something like walking a directed graph -- and remember detect loops.

Such an example does not look bad at all in Tcl -- provided you use the
right data structures.

steve...@gmail.com

unread,
Jun 18, 2012, 10:01:30 PM6/18/12
to r...@controlq.com
On Monday, 18 June 2012 10:12:01 UTC+8, Ben Collver wrote:
> On Sunday, June 17, 2012 3:53:16 PM UTC-7, Rob Sciuk wrote:
> > http://www.controlq.com/blog/wordpress/?p=381
>
> This post compares programming TCL to jumping through flaming hoops.
> https://groups.google.com/d/msg/comp.compilers/6yJBnXzntzQ/z3boS17QtugJ

You quote a 2001 post that quotes a 1995 post. I suggest you look into some of the more recent development in Tcl before you draw conclusions.

Sp...@controlq.com

unread,
Jun 19, 2012, 12:23:17 PM6/19/12
to
On Mon, 18 Jun 2012, steve...@gmail.com wrote:

> Date: Mon, 18 Jun 2012 19:01:30 -0700 (PDT)
> From: steve...@gmail.com
> Cc: r...@controlq.com
> Newsgroups: comp.lang.tcl
> Subject: Re: A bit of tcl advocacy ...
set taboo [list religion politics scripting_languages]


live and learn, I suppose :-)

Cheers,
Rob.

steve...@gmail.com

unread,
Jun 19, 2012, 8:54:25 PM6/19/12
to Sp...@controlq.com
On Wednesday, June 20, 2012 12:23:17 AM UTC+8, (unknown) wrote:

> set taboo [list religion politics scripting_languages]
>
>
> live and learn, I suppose :-)
>
> Cheers,
> Rob.

lappend taboo editors :)

Joe English

unread,
Jun 20, 2012, 3:51:13 PM6/20/12
to
Ben Collver wrote, apropos of nothing in particular:
> Rob Sciuk wrote:
>> http://www.controlq.com/blog/wordpress/?p=381
>
> This post compares programming TCL to jumping through flaming hoops.
> https://groups.google.com/d/msg/comp.compilers/6yJBnXzntzQ/z3boS17QtugJ
>
> The expr factorial example is also discussed in the following patch.
> http://elf.org/etc/tcl-expr-patch.html


The "expr hell" problem has (at long last) been addressed
(in two different ways) in Tcl 8.5.


TIP#232 <URL: http://www.tcl.tk/cgi-bin/tct/tip/232.html >
allows you to extend the set of functions available
in [expr] syntax by simply defining a procedure in
the appropriate namespace.

And TIP#174 <URL: http://www.tcl.tk/cgi-bin/tct/tip/174.html >
allows you to avoid [expr] syntax entirely and write arithmetic
expressions using normal Tcl syntax.

# Old painful way:
proc fib {n} {
if {$n <= 1} {
return 1
} else {
return [expr {[fib [expr {$n-1}]] + [fib [expr {$n-2}]]}]
}
}

# New way, TIP#232:
namespace eval ::tcl::mathfunc {
proc fib {n} { expr { $n <= 1 ? 1 : fib($n-1) + fib($n-2) } }
}


# New way, TIP#174:
namespace import tcl::mathop::*
proc fib {n} {
if {[<= $n 0]} {
return 1
} else {
return [+ [fib [- $n 1]] [fib [- $n 2]]]
}
}

Of course experienced Tcl programmers have been doing things
the TIP#174 way "by hand" for years --

proc + {x y} { expr {$x+$y} }
proc * {x y} { expr {$x*$y} }
... etc. ...

is standard practice when running up against expr hell.
TIP#174 is better, though, since it provides variadic
versions of all the associative operators and various
other Lispy goodness.


--Joe English

Prof Craver

unread,
Jun 21, 2012, 4:26:37 PM6/21/12
to
On Wednesday, June 20, 2012 3:51:13 PM UTC-4, Joe English wrote:

> The "expr hell" problem has (at long last) been addressed
> (in two different ways) in Tcl 8.5.

It's also worth pointing out that "expr hell" tends to happen when you attempt to write a Tcl program the same way you'd write it in an arithmetic language like C.

This standard Fibonacci example looks terrible in Tcl because the standard Fibonacci example is an int function with int arguments. To implement this naively in Tcl, one ends up wrapping everything in an [expr] to keep the expression evaluated as an integer.

However, if one thinks in Tcl, and accepts that arguments are strings, the same algorithm is written:

proc fib n {
set x [expr $n]
if {$x<=1} {return 1}
expr [fib $x-1]+[fib $x-2]
}

--S

Prof Craver

unread,
Jun 21, 2012, 10:17:48 PM6/21/12
to
On Thursday, June 21, 2012 4:26:37 PM UTC-4, Prof Craver wrote:
>
> However, if one thinks in Tcl, and accepts that arguments are strings, the same algorithm is written:
>
> proc fib n {
> set x [expr $n]
> if {$x<=1} {return 1}
> expr [fib $x-1]+[fib $x-2]
> }

Note that one can also implement this logic with a simpler procedure:

proc fib n {
if $n<=1 {return 1}
expr [fib $n-1]+[fib $n-2]
}

Notice the missing braces in the [if] command: $n is not a number, but an expression such as "5-2-1-2", and it must be substituted before [if] is called. Again, there is no "expr hell," because we simply allow the arguments to be strings rather than insisting they be ints at all times.

I should emphasize that this isn't some alternate snazzy clever way to compute fib(n): this is the same bog-standard formula that was likened to jumping through flaming hoops. It's just written without the extra [expr] commands.

Unfortunately, this two-liner is substantially slower than the three-liner above it, because the recursion causes a growth in argument length along with the exponential growth in procedure calls. On my computer, [fib 26] takes about 3 times longer with the 2-line version as it does with the 3-line version.

--S

Ben Collver

unread,
Jun 21, 2012, 11:41:28 PM6/21/12
to
On Thursday, June 21, 2012 7:17:48 PM UTC-7, Prof Craver wrote:
> > However, if one thinks in Tcl, and accepts that arguments are strings, the same algorithm is written:
>
> I should emphasize that this isn't some alternate snazzy clever way to compute fib(n): this is the same bog-standard formula that was likened to jumping through flaming hoops.

That was a pleasant read. Thanks for sharing!

Uwe Klein

unread,
Jun 22, 2012, 5:24:47 AM6/22/12
to
Prof Craver wrote:
> Unfortunately, this two-liner is substantially slower than the three-liner above it, because the
> recursion causes a growth in argument length along with the exponential growth in procedure
> calls. On my computer, [fib 26] takes about 3 times longer with the 2-line version as it does
> with the 3-line version.

#!/usr/bin/tclsh
# fibonacci gyrations
#
lappend fibs A {
if {$n <= 1} {
return 1
} else {
return [expr {[fib [expr {$n-1}]] + [fib [expr {$n-2}]]}]
}
}
lappend fibs B {
set x [expr $n]
if {$x<=1} {return 1}
expr [fib $x-1]+[fib $x-2]
}
lappend fibs C {
if $n<=1 {return 1}
expr [fib $n-1]+[fib $n-2]
}
lappend fibs D {
expr ($n>1)?\[fib $n-1\]+\[fib $n-2\]:1
}
foreach {id body} $fibs {
set res {}
proc fib n $body
set time [ time {
for {set n 0} {$n<20} {incr n} {
lappend res [ fib $n ]
}
} 100 ]
set res {}
for {set n 0} {$n<20} {incr n} {
lappend res [ fib $n ]
}
puts stdout $id\ $time
puts stderr $id\ $res\ $time
}
# end

uwe@james:~/tcltest> ./fibona.tcl 2>numbers.res
A 43057.22 microseconds per iteration
B 746553.7 microseconds per iteration
C 1375928.05 microseconds per iteration
D 1926937.45 microseconds per iteration

The stringy stuff is rearly hard to chew for any cpu ;-).

uwe

Uwe Klein

unread,
Jun 22, 2012, 5:59:19 AM6/22/12
to
> A 43,057.22 microseconds per iteration
> B 746,553.7 microseconds per iteration
> C 1,375,928.05 microseconds per iteration
> D 1,926,937.45 microseconds per iteration
>
> The stringy stuff is rearly hard to chew for any cpu ;-).
>
> uwe
And a solution that recursively accumulates and then unroles in one expr call:
F 175,132.92 microseconds per iteration
foreach loop using incr:
G 162,520.87 microseconds per iteration

set id F
proc fib_h n {
if {$n<=1} {return 1}
set N $n
return [list {*}[fib_h [incr n -1]] {*}[fib_h [incr n -1]] ]
}
proc fib n {
set res [ fib_h $n ]
return [ expr [join $res + ] ]
}
set id G ;# using the same helper proc:
proc fib n {
set res [ fib_h $n ]
set ret 0
foreach e $res {
incr ret $e
}
return $ret
}

all versions return the same result ;-)

uwe

Prof Craver

unread,
Jun 22, 2012, 2:28:27 PM6/22/12
to
On Friday, June 22, 2012 5:24:47 AM UTC-4, Uwe Klein wrote:
>
> The stringy stuff is rearly hard to chew for any cpu ;-).

I guess the constant [expr]ing of the original example ensures that all the passed values are internally represented as ints, and conversion only occurs once at the beginning.

Of course, if we want performance the best bet is

set phi [expr 0.5*(1+sqrt(5.0))]
proc fib n {
expr round(($::phi**($n+1))/sqrt(5.0))
}

Testing as formula F:

A 14185.68608 microseconds per iteration
B 103092.79714 microseconds per iteration
C 197011.0857 microseconds per iteration
D 263744.49952 microseconds per iteration
F 165.68077000000002 microseconds per iteration

Of course, that example skirts the main issue, that of the necessity of "expr hell" to program in Tcl. These examples show that you don't need excessive exprs to express an algorithm, but there may be significant performance penalities if you don't.

--S

Don Porter

unread,
Jun 22, 2012, 2:37:11 PM6/22/12
to
On 06/22/2012 02:28 PM, Prof Craver wrote:
> Of course, that example skirts the main issue, that of the necessity of "expr hell" to program in Tcl. These examples show that you don't need excessive exprs to express an algorithm, but there may be significant performance penalities if you don't.

The tcl::mathop commands compile to the same bytecode as braced [expr].

--
| Don Porter Applied and Computational Mathematics Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|

Gerald W. Lester

unread,
Jun 22, 2012, 8:46:51 PM6/22/12
to
The following is the fastest by a little bit:

lappend fibs E {
if {$n <= 1} {return 1}
expr {[fib [incr n -1]] + [fib [incr n -1]]}
}

I'll leave it as an exercise to the reader to figure out why it works.

Please note, no expr hell.

Andreas Leitgeb

unread,
Jun 22, 2012, 9:12:11 PM6/22/12
to
Gerald W. Lester <Gerald...@KnG-Consulting.net> wrote:
> The following is the fastest by a little bit:
>
> lappend fibs E {
> if {$n <= 1} {return 1}

I haven't followed the thread completely, but the fibonacci
sequence I knew started with fib(0)==0 and fibn(1)==1
yours obviously starts fib(0)==fib(1)==1, which makes
an index-shift by 1.

An easy (and obvious) "fix" would be to return $n for $n<=1

Gerald W. Lester

unread,
Jun 22, 2012, 11:47:31 PM6/22/12
to
Andreas,

All of the ones in the compare had fib(0) == 1.

I wanted to compare apples to apples, so I did the same thing.

Uwe Klein

unread,
Jun 23, 2012, 2:54:04 PM6/23/12
to
Gerald W. Lester wrote:
> The following is the fastest by a little bit:
>
> lappend fibs E2 {
> if {$n <= 1} {return 1}
> expr {[fib [incr n -1]] + [fib [incr n -1]]}
> }
>
lappend fibs E3 {
expr {($n <= 1)?1:[fib [incr n -1]] + [fib [incr n -1]]}
}

E2 41780.73 microseconds per iteration
E3 40961.66 microseconds per iteration

(marginal) improvement.

uwe

Donal K. Fellows

unread,
Jun 25, 2012, 5:59:27 AM6/25/12
to
On 22/06/2012 19:28, Prof Craver wrote:
> Of course, if we want performance the best bet is
>
> set phi [expr 0.5*(1+sqrt(5.0))]
> proc fib n {
> expr round(($::phi**($n+1))/sqrt(5.0))
> }

But it's even better if you put braces round that expression. A little
experimental testing indicates that it makes this about 5 times faster.
Why parse expressions repeatedly when you don't have to?

Donal.

Donal K. Fellows

unread,
Jun 25, 2012, 6:11:56 AM6/25/12
to
You get another improvement (approximately twice as fast again) by doing
this, which allows the "magic" values to be converted into constants in
the bytecode (and it's pretty much an optimal bytecode sequence at the
moment):

proc fib n {
expr {round(((0.5*(1+5**0.5))**($n+1))/5**0.5)}
}

(It's getting trickier to work out how fast it is at this point; I'm
approaching my system jitter level so I think I won't try any more.)

Donal.

Andreas Leitgeb

unread,
Jun 25, 2012, 7:58:29 AM6/25/12
to
Donal K. Fellows <donal.k...@manchester.ac.uk> wrote:
> On 25/06/2012 10:59, Donal K. Fellows wrote:
>> On 22/06/2012 19:28, Prof Craver wrote:
>>> Of course, if we want performance the best bet is
> proc fib n { expr {round(((0.5*(1+5**0.5))**($n+1))/5**0.5)} }

Doing it with floating point means, that results are correct
only till about 70, so for this limited range, hardcoding
the values into an array fib and accessing $fib($n) might
be still a notch faster.

Donal K. Fellows

unread,
Jun 26, 2012, 4:20:46 AM6/26/12
to
[fib 70] is indeed the first wrong value, and a precalculation strategy
is indeed very quick (though a list is faster than an array). My main
interest though was in how the different ways of writing the above piece
of mathemagics would result in changes to the bytecode sequence.

It also turns out to be faster these days to use [global] to bind a
global variable to a local variable instead of using a fully-qualified
variable name, even for a single access. What's more, [variable] is even
faster again. This is somewhat unexpected, and likely to change how I
write code in the future. (Checked in 8.5 and 8.6 with both optimized
and debugging builds, and consistently true.)

Donal.

Andreas Leitgeb

unread,
Jun 26, 2012, 5:20:42 AM6/26/12
to
Donal K. Fellows <donal.k...@manchester.ac.uk> wrote:
> On 25/06/2012 12:58, Andreas Leitgeb wrote:
>> Donal K. Fellows <donal.k...@manchester.ac.uk> wrote:
>>> On 25/06/2012 10:59, Donal K. Fellows wrote:
>>>> On 22/06/2012 19:28, Prof Craver wrote:
>>>>> Of course, if we want performance the best bet is
>>> proc fib n { expr {round(((0.5*(1+5**0.5))**($n+1))/5**0.5)} }
>> Doing it with floating point means, that results are correct
>> only till about 70, so for this limited range, hardcoding
>> the values into an array fib and accessing $fib($n) might
>> be still a notch faster.
> [fib 70] is indeed the first wrong value, and a precalculation strategy
> is indeed very quick (though a list is faster than an array).

Array access is less verbose than lindex, though ;-)

> My main interest though was in how the different ways of writing
> the above piece of mathemagics would result in changes to the
> bytecode sequence.

The improvement by bracing was to be expected, but I admit, Ι didn't
expect the effect of inlining the constant's formula.

Makes me brainstorm about tcl::mathconst ;-) Those "consts" would,
if changed, increment the generation-counter and cause recompilation
of all, but allow inlining their value into compiled expressions.

> It also turns out to be faster these days to use [global] to bind a
> global variable to a local variable instead of using a fully-qualified
> variable name, even for a single access. What's more, [variable] is even
> faster again.

I typically "declare" (really link in) a couple of global variables in
one global statement, and that isn't equally possible with variable,
unless I also want to initialize each but maybe the last one.

> This is somewhat unexpected, and likely to change how I
> write code in the future. (Checked in 8.5 and 8.6 with both optimized
> and debugging builds, and consistently true.)

What prevents global from being optimized similarly?

Donal K. Fellows

unread,
Jun 26, 2012, 6:45:31 AM6/26/12
to
On 26/06/2012 10:20, Andreas Leitgeb wrote:
> What prevents global from being optimized similarly?

I don't know. Investigation needed. :-)

Donal.

Donal K. Fellows

unread,
Jun 26, 2012, 10:36:09 AM6/26/12
to
OK, there are some subtle differences between how [global] and
[variable] handle the realization of variables ([global] is instead like
[namespace upvar]) which leads to differences in exactly what is
reported by [info vars] in some cases. I don't think this matters in the
vast majority of cases, but it's spotted by the Tcl test suite so I
won't make the change in compilation strategy.

You can use [variable] yourself though. I know I will. :-)

Donal.


Andreas Leitgeb

unread,
Jun 27, 2012, 9:46:00 AM6/27/12
to
Donal K. Fellows <donal.k...@manchester.ac.uk> wrote:
> On 26/06/2012 11:45, Donal K. Fellows wrote:
>> On 26/06/2012 10:20, Andreas Leitgeb wrote:
>>> What prevents global from being optimized similarly?
>> I don't know. Investigation needed. :-)
> OK, there are some subtle differences between how [global] and
> [variable] handle the realization of variables ([global] is instead like
> [namespace upvar]) which leads to differences in exactly what is
> reported by [info vars] in some cases.

I tried a few scenarios and couldn't find a relevant difference,
except for where the variable is linked from and whether it is
eventually initialized.
I made procs
proc foo {} { variable foo; return [info vars][info exists foo] }
proc goo {} { global foo; return [info vars][info exists foo] }
put them at global level, and into a namespace, and tried with
or without predefining the variables outside the proc, the
results were always essentially the same. I guess, I must
have missed something.

> but it's spotted by the Tcl test suite so I won't make the
> change in compilation strategy.

Which particular test do you mean?

> You can use [variable] yourself though. I know I will. :-)

Critical code should use namespaced variables in favour of
globals, anyway. Quick-hack scripts, which Tcl is also really
good for, won't really notice the speed-difference. ;-)

My interest in the difference is more about the seemingly
redundant semantic complexity, performing similar tasks
in quite different ways...

Donal K. Fellows

unread,
Jun 28, 2012, 5:59:10 AM6/28/12
to
On 27/06/2012 14:46, Andreas Leitgeb wrote:
>> but it's spotted by the Tcl test suite so I won't make the
>> change in compilation strategy.
>
> Which particular test do you mean?

Thankfully, it's still in my scrollback. :-)

info-19.3, namespace-old-7.4, namespace-old-7.7

It appears to be related to what variables are reported by [info vars],
which can observe the difference between [global] and [variable] under
normal circumstances. I dislike that that's possible at all, but I'm not
volunteering to clean that mess out in the near future. (There are a few
places in Tcl where it's hard to work out what exactly should be
happening in all the gnarly edge cases. This is one of those places.)

Donal.

Andreas Leitgeb

unread,
Jun 30, 2012, 11:51:15 AM6/30/12
to
Donal K. Fellows <donal.k...@manchester.ac.uk> wrote:
> On 27/06/2012 14:46, Andreas Leitgeb wrote:
>>> but it's spotted by the Tcl test suite so I won't make the
>>> change in compilation strategy.
>> Which particular test do you mean?
> Thankfully, it's still in my scrollback. :-)
> info-19.3, namespace-old-7.4, namespace-old-7.7

I'm not sure I understand the problem. These tests check, that
some variables previously [global]ed, show up in [info vars].

But they also do with [variable] instead of [global], so what
behavioural difference is supposed to be observable and tested ?

> It appears to be related to what variables are reported by [info vars],
> which can observe the difference between [global] and [variable] under
> normal circumstances.

But [info vars] *does* see [variable]-imported locals,
just like it sees [global]-imported ones.

% namespace eval foo { proc foo {} { variable foo; puts [info vars][info exists foo] }}
% foo::foo
foo0
%

rogercr...@gmail.com

unread,
Jul 1, 2012, 4:07:01 AM7/1/12
to
On Monday, June 18, 2012 1:30:32 AM UTC-6, Uwe Klein wrote:
> Ben Collver wrote:
> > On Sunday, June 17, 2012 3:53:16 PM UTC-7, Rob Sciuk wrote:
> >
> >>http://www.controlq.com/blog/wordpress/?p=381
> >
> >
> > This post compares programming TCL to jumping through flaming hoops.
> > https://groups.google.com/d/msg/comp.compilers/6yJBnXzntzQ/z3boS17QtugJ
> >
> > The expr factorial example is also discussed in the following patch.
> > http://elf.org/etc/tcl-expr-patch.html
>
> Certainly very deep philosophy ;-)
>
> "
> Access denied
> user warning: Incorrect key file for table './elf115_elf/role.MYI'; try to repair it query: SELECT
> p.perm FROM role r INNER JOIN permission p ON p.rid = r.rid WHERE r.rid IN (1) in
> /usr/www/users/elf115/www.elf.org/html/modules/user/user.module on line 502.
> user warning: Incorrect key file for table './elf115_elf/cache_content.MYI'; try to repair it query:
> SELECT data, created, headers, expire, serialized FROM cache_content WHERE cid =
> 'content_type_info:en' in /usr/www/users/elf115/www.elf.org/html/includes/cache.inc on line 26.
> <about 1000% more trash snipped>
> "
>
> now what programming language does spout that kind of gibberish?
>
> uwe

Bummer, the page loaded fine for me this morning. I was very impressed by the arguments, most of which I don't remember making.

You want gibberish, you can have the snit tracebacks I've been dealing with for the past few months.

-- rec --

Uwe Klein

unread,
Jul 1, 2012, 8:56:31 AM7/1/12
to
yes. loading nicely at the moment So Jul 1 14:56:15 CEST 2012
>
> You want gibberish, you can have the snit tracebacks I've been dealing with for the past few
> months.
;-)
>
> -- rec --
uwe

Donal K. Fellows

unread,
Jul 2, 2012, 8:16:02 AM7/2/12
to
On 30/06/2012 16:51, Andreas Leitgeb wrote:
> I'm not sure I understand the problem. These tests check, that
> some variables previously [global]ed, show up in [info vars].
>
> But they also do with [variable] instead of [global], so what
> behavioural difference is supposed to be observable and tested ?

I think it relates to variables that were [global]led, but not [set] (or
that were [unset]). It's pretty deeply gnarly.

Donal.

Bruce Johnson

unread,
Jul 10, 2012, 9:09:01 AM7/10/12
to
On Sunday, July 1, 2012 4:07:01 AM UTC-4, Roger Critchlow wrote:
> On Monday, June 18, 2012 1:30:32 AM UTC-6, Uwe Klein wrote:
> &gt; Ben Collver wrote:
> &gt; &gt; On Sunday, June 17, 2012 3:53:16 PM UTC-7, Rob Sciuk wrote:
> &gt; &gt;
> &gt; &gt;&gt;http://www.controlq.com/blog/wordpress/?p=381
> &gt; &gt;
> &gt; &gt;
> &gt; &gt; This post compares programming TCL to jumping through flaming hoops.
> &gt; &gt; https://groups.google.com/d/msg/comp.compilers/6yJBnXzntzQ/z3boS17QtugJ
> &gt; &gt;
> &gt; &gt; The expr factorial example is also discussed in the following patch.
> &gt; &gt; http://elf.org/etc/tcl-expr-patch.html
> &gt;
> &gt; Certainly very deep philosophy ;-)
> &gt;
> &gt; &quot;
> &gt; Access denied
> &gt; user warning: Incorrect key file for table &#39;./elf115_elf/role.MYI&#39;; try to repair it query: SELECT
> &gt; p.perm FROM role r INNER JOIN permission p ON p.rid = r.rid WHERE r.rid IN (1) in
> &gt; /usr/www/users/elf115/www.elf.org/html/modules/user/user.module on line 502.
> &gt; user warning: Incorrect key file for table &#39;./elf115_elf/cache_content.MYI&#39;; try to repair it query:
> &gt; SELECT data, created, headers, expire, serialized FROM cache_content WHERE cid =
> &gt; &#39;content_type_info:en&#39; in /usr/www/users/elf115/www.elf.org/html/includes/cache.inc on line 26.
> &gt; &lt;about 1000% more trash snipped&gt;
> &gt; &quot;
> &gt;
> &gt; now what programming language does spout that kind of gibberish?
> &gt;
> &gt; uwe
>
> Bummer, the page loaded fine for me this morning. I was very impressed by the arguments, most of which I don&#39;t remember making.
>
> You want gibberish, you can have the snit tracebacks I&#39;ve been dealing with for the past few months.
>
> -- rec --

The "=" command of the AMath package for JTcl ( http://wiki.tcl.tk/36463 ) was definitely influenced by your expr patch proposal ( http://elf.org/etc/tcl-expr-patch.html ). It allows commands like:

set y [= 3*a+b]

(and variables can be vectors and matrices).

Bruce


Prof Craver

unread,
Jul 10, 2012, 11:36:30 AM7/10/12
to
On Tuesday, July 10, 2012 9:09:01 AM UTC-4, Bruce Johnson wrote:

> The &quot;=&quot; command of the AMath package for JTcl ( http://wiki.tcl.tk/36463 ) was definitely influenced by your expr patch proposal ( http://elf.org/etc/tcl-expr-patch.html ). It allows commands like:
>
> set y [= 3*a+b]

I guess there's also the "Let unknown know" example from the Tcl Wikibook, which attempts to evaluate unknown commands as arithmetic expressions. Here's the code from the book:

proc know what {
if ![info complete $what] {error "incomplete command(s) $what"}
proc unknown args $what\n[info body unknown]
} ;# RS

% know {if {![catch {expr $args} res]} {return $res}}
% 3+4
7

In other words, you can leave the "expr" out entirely, as long as you are willing to endure the performance hit of [unknown] being called whenever you want to evaluate an arithmetic expression (and some expressions don't exactly work the same way either). In any case, once you do this, you can write the original code as

proc fib {n} {
if {$n < 2} { return 1 } else { return [[fib [$n-2]] + [fib [$n-1]]] }
}

This replaces "expr hell" with "bracket purgatory"

--S
0 new messages