07-25-2014, 10:16 +0200
AuthorPost
thommey  09-14-2006, 18:50   | Why you should use braces {} around expressions. Jabber
(Administrator)
Member since 03/2004
61 Posts
German translation: Scroll down!


First of all you should be aware that 2 common cases fit the statement "expression".
Case 1: expr (the obvious one)
                                                                                                                              
1
proc multiply {a b} { return [expr $a * $b] }

Case 2: If-condition. If-conditions are evaluated similar to "expr". That's the reason you can use mathematic expressions (1 + $var < 5) in the if-condition:
                                                                                                                              
1
if {$a * $b == 10} { puts "Ok" }


When you learned the Tcl syntax, you usually place these braces around "$a*$b==10" in the if condition just because it's the thing you've read in the manual and other languages aren't as simple as Tcl syntaxwise. So in other language you usually just learn the if-syntax by heart.
Maybe you already found out, that you can drop them. The statement:
                                                                                                                              
1
if {[string is integer $a]} { .. }

apparently does the same as
                                                                                                                              
1
if [string is integer $a] { .. }

but it doesn't.

Now let's get to the reason you most like want to use if {..} and expr {..}.
Why {} around the statement? What's the difference?

In Tcl, {} group words like "" do, but they prevent substitution of variables, command and backslash-expressions. Compare set a "hello $var" and set a {hello $var} for example. The latter will return "hello $var" but in the first one $var will be replaced by its content. Read more in the Tcl syntax definition (Rule 4,6)

This takes time and causes the statement to get double-evaluated.
Now we apply that logic to expr:
                                                                                                                              
1
set a 4; set b 2; puts [expr $a*$b] ---> "8"

                                                                                                                              
1
set a 4; set b 2; puts [expr {$a*$b}] ---> "8".. note: it does NOT return "$a*$b" but "8"!


But why? Because expr evaluates its argument(s)!
expr replaces variables by its values ($var)
expr replaces commands by its values ([command])
expr replaces substitutions by its values (\n or x84)
just like enclosing an argument in double quotes would.


As I already mentioned above, this takes time. expr {$a * $b} is faster, because with expr $a * $b, the interpreter replaces $a and $b by their values, passes "2 * 4" to expr, and expr then evaluates this. Expr can do that faster if it doesn't attempt to substitute variables/commands/... another time.

But there's a much more severe problem than the evaluation time... (which usually doesn't matter that much in network applications anyway)

The security.
Imagine the following proc again:
                                                                                                                              
1
proc multiply {a b} { return [expr $a*$b] }


and we call it like:
multiply 2 4 -> 8

multiply {[exit]} 4 -> EXIT

Tcl will exit. Because expr evaluates the content {[exit] * 4} itself again, replacing [exit] by the return value of evaluating the command exit.

So, in fact:
                                                                                                                              
1
proc multiply {a b} { return [expr {$a * $b}] }


is faster and prevents security holes which the other version has!
That's why our syntax checker in our pastebin complains about it.


YOU SHOULD USE expr {.....}, unless you need the double-evaluation (rare but possible).
(for computation time improvement and common [die]/[exit]-bug prevention)


See also: http://wiki.tcl.tk/10225
This post was edited 6 times, last on 08-02-2010, 11:48 by thommey
thommey  09-14-2006, 19:06   | Warum man geschweifte Klammern {} um expressions benutzen sollte. Jabber
(Administrator)
Member since 03/2004
61 Posts
Als Erstes möchte ich mal klar stellen, dass es 2 häufige Vorkommnisse gibt, in denen expressions vorkommen.
Fall 1: expr (das offensichtliche)
                                                                                                                              
1
proc multipliziere {a b} { return [expr $a * $b] }

Fall 2: If-Bedingung. Vielleicht weiß man es schon, oder nicht. If-Bedingungen werden mit expr ausgewertet. Das ist auch der Grund, warum überhaupt solche Bedingungen wie {1 + $var < 5} möglich sind.
                                                                                                                              
1
if {$a * $b == 10} { puts "Ok" }


Als ihr die TCL Syntax gelernt habt, habt ihr vermutlich diese geschweiften Klammern einfach mit der Syntax auswendig gelernt und es übernommen.
Nach einiger Übung könnte man aber eventuell darauf gekommen sein, sie wegzulassen.

Die If-Bedingung:
                                                                                                                              
1
if {[string is integer $a]} { .. }

macht ja scheinbar das gleiche wie
                                                                                                                              
1
if [string is integer $a] { .. }

aber das tut sie NICHT.

Jetzt werde ich erklären, warum man {} benutzen sollte, sowohl um die If-Bedingung, als auch um das Argument an expr.
Was ist also der Sinn und Zweck der Klammern?
Ich gehe davon aus, dass ihr bereits den Unterschied zwischen set a "hallo $var" und set a {hallo $var} kennt. Letzteres setzt die Variable 'a' auf den Wert: "hallo $var", aber im ersten Fall wird $var durch den tatsächlichen Variableninhalt ersetzt.

Diese Ersetzung kostet Zeit und führt auch zu einer Doppel-Auswertung.

Ein Beispiel:
                                                                                                                              
1
set a 4; set b 2; puts [expr $a*$b] ---> "8"

Something failed while rendering code in this thread, please inform #tcl on QuakeNet. Thank you.
Aber warum? Weil expr das Argument erneut verarbeitet/auswertet!
expr ersetzt Variablen durch ihren Inhalt ($var)
expr ersetzt Funktionen durch ihren Return-Wert ([command])
expr ersetzt Backslash-Schreibweisen durch ihre Werte (\n oder x84)


Wie ich oben bereits gesagt habe, das kostet ZEIT. expr {$a * $b} _ist_ schneller. Weil der Interpreter nicht erst "$a * $b" durch "2 * 4" ersetzt, und dann anschließend expr erneut guckt, ob etwas zu ersetzen ist.

Aber es gibt noch ein viel größeres Problem als Rechenzeit ..(wer schnelle Rechenzeit braucht, benutzt sowieso nicht unbedingt TCL :)

Die SICHERHEIT!
Folgendes Beispiel nochmal:
                                                                                                                              
1
proc multipliziere {a b} { return [expr $a*$b] }


and we call it like:
multipliziere 2 4 -> 8

multipliziere "\[exit\]" 4 -> EXIT

Tcl wird sich beenden. Weil expr den Inhalt wieder auswertet.

Also:
                                                                                                                              
1
proc multipliziere {a b} { return [expr {$a * $b}] }


ist schneller und hat KEINE Sicherheitslücken im Gegensatz zur alten Version.
Deswegen schlägt unser Syntaxchecker alarm wenn keine Klammern da sind.


MAN SOLLTE expr {.....} NUTZEN, WENN MAN NICHT WIRKLICH DIE DOPPELAUSWERTUNG BRAUCHT.
(für kürzere Rechenzeit und vor allem zur Vermeidung der bekannten [die]-Bugs)


Weitere Informationen: http://wiki.tcl.tk/10225
This post was edited 4 times, last on 09-30-2006, 11:33 by thommey
Advanced options for this topic:

Ignore this topic (Do not list this topic in the "unread topics" search. You are currently not ignoring this topic.)
Hide this topic (Hidden topics are not displayed in the topics list. This topic is currently not hidden.)
Go to forum

Unclassified NewsBoard 1.5.3-d | © 2003-4 by Yves Goergen