Forum OpenACS Development: Re: Language lawyering

Collapse
7: Re: Language lawyering (response to 1)
Posted by Don Baccus on
The latter was the reasoning and in fact apparently aD and OpenACS folk were unaware of "eq"/"ne".  I know I was until you pointed this out - I've been using "string equal" ...

Sounds like we could clean up our code a bit.  Also our general way of writing "set" expressions is sub-optimal, I know folks in general seem to realize it's good practice to surround your "if" expr in curly-braces, but I'd never thought about the fact that the same is true of "set".  We aren't getting full speed from the bytecode compiler it appears:

"Enclose expressions in braces for the best speed and the smallest storage requirements. This allows the Tcl bytecode compiler to generate the best code.

As mentioned above, expressions are substituted twice: once by the Tcl parser and once by the expr command. For example, the commands

set a 3
set b {$a + 2}
expr $b*4

return 11, not a multiple of 4. This is because the Tcl parser will first substitute $a + 2 for the variable b, then the expr command will evaluate the expression $a + 2*4.

Most expressions do not require a second round of substitutions. Either they are enclosed in braces or, if not, their variable and command substitutions yield numbers or strings that don't themselves require substitutions. However, because a few unbraced expressions need two rounds of substitutions, the bytecode compiler must emit additional instructions to handle this situation. The most expensive code is required for unbraced expressions that contain command substitutions. These expressions must be implemented by generating new code each time the expression is executed."

The "gotcha" seems awful until you realize that AFAIK we've never been bit by it in "if" statements ...

Collapse
8: Re: Language lawyering (response to 7)
Posted by Alfred Werner on
Don, it gets worse :)

Following your example from the docs -

$tclsh
% info tclversion
8.4
% set a 3
3
% set b {$a + 2}
$a + 2
% expr $b * 4
11
% if {$b * 4 == 11} {puts "yep"}
can't use non-numeric string as operand of "*"
% if {11 == $b * 4} {puts "yep"}
can't use non-numeric string as operand of "*"
% if {[expr $b * 4] == 11} {puts "yep"}
yep

Yikes! Damned if you do - damned if you don't. Or at least if you do - you have to do more than what might seem obvious at first reading.

It is worth noting that if you try:
set b $a + 2  it is an error - set takes only two operands/parameters
set b [expr $a + 2] is the correct form. So if you were INTENDING to defer the math and just pass the formula in some recursive lisp-ish type of way then you'd need to remember to later [expr] it.

I guess this is just a cautionary note for anyone introducing braces in their code without first really understanding the deep voodoo at work. OTOH, I think it would be safe to change a lot of == to eq within if clauses, and should the code break, there was probably something wrong-ish to begin with.