DebuggingExprCalls

rwm notes: It can sometimes be difficult to debug expr calls in deeply nested code. The expr has several variables, and one is invalid causing the expr to throw an error. The typical response is to start adding puts to the code to instrument each call then find offending one. This page gives a different way to solve this problem.

Example problem:

 set a 1
 set b {}  ;# <---- this represents bad data from elsewhere

 expr {$a+$b}
 can't use empty string as operand of "+"

(note this is the result from Tclsh8.5)

Which doesn't tell us which part of the expression was bad

By replacing the expr command we can catch the error and try harder to help by showing the entire expression. Often complex expressions will have many "+" (as the example) operators and we don't know which had a bad operand.

set _debugExpr_ 1

if {[info exists _debugExpr_]} {
  rename expr _expr
  proc expr {args} {
    if {[catch {set result [uplevel _expr $args]}]} {
      error [uplevel list "error in expression: '" {*}$args "'"]
    }
    set result
  }
}

% expr {$a+$b}
error in expression: ' 1+ '

Beware, this comes at the price of speed:
% time {expr $a/.5} 1000
25.975 microseconds per iteration
% time {_expr $a/.5} 1000
17.065 microseconds per iteration
% time {expr {$a/.5}} 1000
15.988 microseconds per iteration
% time {_expr {$a/.5}} 1000
0.709 microseconds per iteration