2

This may sound silly. Bear with me. While playing around with expr, I came across the following scenario

proc badExpr { a b } { 
    return expr $a+$b
}

proc goodExpr { a b } { 
    return [ expr {$a+$b} ]
}

puts "Bad Expression Result : --->[ badExpr 1 3 ]<-----"
puts "Good Expression Result : [ goodExpr 1 3 ]"

Output:

Bad Expression Result : ---><-----
Good Expression Result : 4

As you can see, the proc badExpr is returning an empty string. Just out of curiosity, I am interested to know why it is returning an empty string ?

Dinesh
  • 16,014
  • 23
  • 80
  • 122

3 Answers3

2

(1) proc badExpr { a b } { return expr $a+$b }

In your badExpr above you are not using the TCL expr command. There expr above is treated just like any other string. If you do want to use the command expr you must put it in square brackets. So it should be return [expr $a + $b]

The return command returns one string value and you can also specify various options. As per the documentation below from http://www.tcl.tk/man/tcl/TclCmd/return.htm the last value is the actual return result.

return ?result?
return ?-code code? ?result?
return ?option value ...? ?result?

However if you have even number of arbitrary args it doesn't return anything. I am not sure what's going on under the hood but when you use either -code or option you would have a value parameter associated with it. So it seems it may be treating each pair as option/value or code/value and returning the last unassociated item as the result.

#Returns 3
return 1 2 3 4 3

#Returns nothing
return 1 2 3

(2) The reason expr {$a+$b} works is because it is the last expression in the proc. If a procedure doesn't execute an explicit return, then its return value is the value of the last command executed in the procedure's body. And it doesn't need to be expr {$a+$b}, it can be expr $a+$b as in your badExpr.

user3885927
  • 3,363
  • 2
  • 22
  • 42
1

In short, the problem is that you don't have brackets around your invocation of expr.

return expr $a+$b   ;# no worky
return [expr $a+$b] ;# works (but you should have braces around the arguments)

It's not clearly documented, but it seems that return accepts an arbitrary number of arguments. If the argument list is even-sized, the command returns the empty string. If the number of arguments is odd, it returns the last argument. This is consistent with the documentation: the normal argument list consists of an optional result value preceded by zero or more option name/value pairs. It's still a little unexpected since one would suppose that the option names were constrained to the useful ones.

Oh! And if return is the last command in a script and its only argument is a script evaluation (code within brackets), you can always skip the return (the byte compiler will eliminate it anyway).

proc goodExpr { a b } { 
    return [ expr {$a+$b} ]
}

is the same as

proc goodExpr { a b } { 
    expr {$a+$b}
}

Documentation: expr, return

Peter Lewerin
  • 13,140
  • 1
  • 24
  • 27
1

Funnily enough, a badExpr would be like this:

proc badExpr { a b } { 
    return [expr $a+$b]
}

What you've actually got is is weirdExpr:

proc badExpr { a b } { 
    return expr $a+$b
}

What does this really do? It sets things in the result dictionary. Tcl results should really be considered to be a triple of three things: a result code (a small integer, in this case 0 for OK — 1 would be for a thrown error, and there are few other ones you can usually ignore) a result value (what you normally return) and a result dictionary. The result dictionary is used mainly with errors, to hold things like the stack trace (used to populate the errorInfo global variable), the line number on which an error occurred, a computer-readable description of the error (used to populate the errorCode global variable), etc., but it can hold any old thing. And you're putting something really odd into it (because that's how return works); the system-defined keys all begin with a - to make them look like ordinary options (and the dictionary itself is often called the option dictionary).

Let's show this using the two-variable form of catch (the second variable catches the dictionary):

% proc weirdExpr { a b } { 
    return expr $a+$b
}
% catch {weirdExpr 1 3} p q
0
% puts $p
% puts $q
expr 1+3 -code 0 -level 0

Yes, there's a funny entry in there called expr whose value is 1+3

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