the if statement in TCL
Asked Answered
L

4

15

I have a question about if statement in tcl of the following code:

if {(($number == 1)&&($name == "hello")) || (($number == 0)&&($name == "yes"))} {
    #do something here
}

The above code works, but if I wrote it down like this:

if {{$number == 1 && $name == "hello"} || {$number == 0&&$name == "yes"}} {
    #do something here
}

It complains that the $number is expected to be a boolean, why? Is the second one not a valid expression? How to correct it?

Lionel answered 29/6, 2012 at 11:5 Comment(0)
M
37

Braces, {}, and parentheses, (), are not interchangeable in Tcl.

Formally, braces are (with one exception) a kind of quoting that indicates that no further substitutions are to be performed on the contents. In the first case above, this means that that argument is delivered to if without substitution, which evaluates it as an expression. The expression sub-language has a strongly-analogous brace interpretation scheme to general Tcl; they denote a literal value with no further substitutions to perform on it.

By contrast, parentheses are mostly not special in Tcl. The exceptions are in the names of elements of arrays (e.g., $foo(bar)), in the expression sublanguage (which uses them for grouping, as in mathematical expressions all over programming) and in the regular expression sublanguage (where they are a different type of grouping and a few other things). It is entirely legal to use parentheses — balanced or otherwise — as part of a command name in Tcl, but you might have your fellow programmers complaining at you anyway for writing confusing code.

The Specifics

In this specific case, the test expression of this if:

if {{$number == 1 && $name == "hello"} || {$number == 0&&$name == "yes"}} {...}

is parsed into:

blah#1 LOGICAL_OR blah#2

where each blah is a literal. Unfortunately, blah#1 (which is exactly equal to $number == 1 && $name == "hello") has no boolean interpretation. (Nor does blah#2 but we never bother to consider that.) Things are definitely going very wrong here!

The simplest fix is to change those bogus braces back to parentheses:

if {($number == 1 && $name == "hello") || ($number == 0&&$name == "yes")} {...}

I bet this is what you originally wanted.

Warning: Advanced Topic

However, the other fix is to add in a little extra:

if {[expr {$number == 1 && $name == "hello"}] || [expr {$number == 0&&$name == "yes"}]} {...}

This is normally not a good idea — extra bulk for no extra gain — but it makes sense where you're trying to use a dynamically-generated expression as a test condition. Do not do this unless you're really really certain you need to do this! I mean it. It's a very advanced technique that you hardly ever need, and there's often a better way to do your overall goal. If you think you might need it, for goodness' sake ask here on SO and we'll try to find a better way; there's almost always one available.

Matrimony answered 29/6, 2012 at 12:55 Comment(0)
B
1

I think the error message you are getting does not mean that $number has to be a boolean (I got the message expected boolean value but got "$number == 1 && $name == "hello""). It means that the string $number == 1 && $name == "hello" is not a boolean value - which is definitely true. If you use curly braces in your if expression those strings are not evaluated but are simply interpreted as they are - as a string of characters.

Benefactor answered 29/6, 2012 at 12:29 Comment(1)
@ratzip The first one looks fine. It has more parentheses than you strictly need, but they don't hurt in expressions as they're compiled out.Matrimony
N
1

In short: if uses a special "mini language" for its condition script — the same understood by the expr command. This is stated in the if manual page:

The if command evaluates expr1 as an expression (in the same way that expr evaluates its argument).

In contrast to Tcl itself, which is quite LISP-like and/or Unix shell-like, that "expr mini language" is way more "traditional" in the sense it feels like C.

Nippon answered 29/6, 2012 at 16:9 Comment(0)
R
1

In ($number == 1) number is assigned 1 and the comparison is made.Ex: 1==1 here output is Boolean. But in {$number == 1 && $name == "hello"} $number is not assigned because of flower bracket $number is compared with 1 so output obtained is not Boolean.

Ruggiero answered 11/12, 2014 at 6:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.