2

I have noticed something. Let's look at two codes bit. in 1, if is not input with a curly brace input, the other is. The curly braced 1 is slightly faster. Why?
See codes and outputs below:

puts [ time { if { [ expr { 5 % 2 } ] } { puts 1 } else { puts 2 } } ]
1
52 microseconds per iteration
puts [ time { if [ expr { 5 % 2 } ] { puts 1 } else { puts 2 } } ]
1
54 microseconds per iteration

The differences are stable. 2 microseconds faster when using more code characters.
Why?

user1134991
  • 3,003
  • 2
  • 25
  • 35
  • You don't need the extra `expr` inside the `if` so that could also be written as `if {5 % 2} { puts 1} {puts 2}`. And the bytecode compiler will remove that expression and replace it with a constant anyway. – schlenk May 01 '15 at 16:30
  • [See also](http://stackoverflow.com/q/17451671/720999). – kostix May 01 '15 at 17:41

3 Answers3

3

Just like expr, bracing the expr of if makes your code faster/more efficient. Basically, without the braces, I quote the wiki link above, the expr may undergo unexpected conversions numeric -> string -> numeric, you can lose precision, your expressions will be much slower, and you can even have security problems.

Quoting a different wiki:

Question: Does the evaluation of expr1 by if differ from how expr evaluates its arguments?

Answer: No, expr in if is processed exactly the same as an argument to expr

DKF: They use the same parser and bytecode generator. Main difference is that expr concatenates its arguments before parsing, but if requires a single argument.

Jerry
  • 70,495
  • 13
  • 100
  • 144
3

Timing something once isn't very useful: let it run 10000 times

Putting the commands in a proc: (removing the inner puts commands to eliminate the noisy output)

proc time_it {n} {
  # bracing the command
  puts [time {if {[expr {5%2}]} {expr 1} else {expr 2}} $n]
  # unbraced
  puts [time {if [expr {5%2}] {expr 1} else {expr 2}} $n]
  # removing the unnecessary `expr` command altogether
  puts [time {if {5%2} {expr 1} else {expr 2}} $n]
}

Then, run it once, two times

% time_it 1
89 microseconds per iteration
27 microseconds per iteration
45 microseconds per iteration
% time_it 1
3 microseconds per iteration
8 microseconds per iteration
1 microseconds per iteration

I assume there's some compilation going on during the first run. The un-braced code is slowest during the 2nd run. Now, time it over a bunch of iterations.

% time_it 1000
0.27 microseconds per iteration
1.245 microseconds per iteration
0.267 microseconds per iteration
% time_it 10000
0.2823 microseconds per iteration
1.2491 microseconds per iteration
0.2198 microseconds per iteration
% time_it 100000
0.28989 microseconds per iteration
0.80064 microseconds per iteration
0.11543 microseconds per iteration
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
3

When you put braces around an expression, especially when you use variable parts in that expression, Tcl becomes able to determine at script compilation time what the semantics of the expression are. This allows it to generate bytecode for the expression and makes everything rather more rapid when it comes to actually running the code.

Without the braces, the compiler probably has to fall back to just issuing instructions to compile and run the expression at runtime. That is, it basically puts off really compiling things until later. This isn't as fast, obviously, since analysing things just isn't ever going to be free. (It can also have other issues, such as allowing security trouble.)

In your specific example, the differences aren't very profound. For real scripts, it can easily double or triple the speed they run at if you get the braces in right. Faster and safer and still easy to write? What's not to like!

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215