Ratnendra Pandey
Ratnendra Pandey

Reputation: 83

How to make a test condition work in TCL

% set HI 1
1
% if { [ info exists HI] && { $HI == 1 } } { puts "Hello World "}
can't use non-numeric string as operand of "&&"
%   

Either of the conditions can be tested alone. How to make the && of the tests work in TCL?

This alone works

% if  { $HI == 1 }  { puts "Hello World "}
Hello World

And this works alone too.

% if { [ info exists HI]  } { puts "Hello World "}
Hello World

Upvotes: 1

Views: 1316

Answers (4)

Donal Fellows
Donal Fellows

Reputation: 137567

In a Tcl expression, {} enclose a non-substituted literal. (Or a variable name if there's a $ immediately before.) When you have an expression inside, that indicates that you should do either one of these:

  • Change the {} to (); parentheses have their normal mathematical interpretation inside expressions.
  • Change the {} to [expr {}] so that the expression is really interpreted as such.

The bytecode out of the two cases is virtually identical, so in performance terms it's a wash. You should write whichever is clearer to you. (Myself, I hardly ever use the second form, reserving nesting [expr] in an expression context for cases where I want to have a non-constant expression fragment. That's actually pretty rare.)

Upvotes: 1

Marco Pallante
Marco Pallante

Reputation: 4043

The second part of your test, that is

{ $HI == 1 }

is wrong, because I suppose you made a confusion about the meaning of braces in Tcl. Braces are not the same of ( ... ), they can't be used in a mathematical expression to change the priority used in evaluation.

Braces are used to compose a string containing spaces and make it appear as a single argument to a Tcl command, but without performing substitutions inside of it.

In your case, the $HI is not substituted with the value of the HI variable, so you are forming a string containing all the exact characters you see inside the braces, including the leading and the trailing spaces.

If you do

if {{ $HI == 1 } eq {$HI == 1}} {
    puts "same"
} else {
    puts "not the same"
}

you'll get not the same as result. (The eq performs string comparison inside an expression.)

You wan't get the right meaning neither if you use the double quote character as string delimiter, that is

" $HI == 1 "

In this case, your variable is actually substituted with its value, so its like you have directly written (supposing $HI is 1, as in your code):

" 1 == 1 "

but it's string, again.

Why Tcl complains? As it says, you are trying to use a non numeric string as operand of &&, and { $HI == 1 } is not numeric because there is no way to see is as a number, so Tcl can't convert to a true/false value depending on the number (false if 0, true if not 0), and the error occurs.

I think what you really wanted to write was

if { [ info exists HI] && ( $HI == 1 ) } { puts "Hello World "}
#                         ^          ^
#                         |__________|____ note ( ) instead of { }

to give higher priority to the == with respect to &&, or to make the conditional more clear. expr, which is implicitly called inside the test condition of an if, knows about the round brackets with the same meaning you find in other programming languages and in math: changing the evaluation order.

As it has been pointed out in other answers and comments, you really don't need the brackets, there, because (as in C and many other languages) the equal operator == has a higher priority than the boolean and &&. But if you want, you can use ( ... ) without fear:

if {2 - 1 * 2} { puts yes } { puts no }

gives no, because the expression is evaluated as 2 - (1 * 2) which is 0.

if {(2 - 1) * 2} { puts yes } { puts no }

gives yes because (2 - 1) * 2 is 2.

Upvotes: 5

Andrew Cheong
Andrew Cheong

Reputation: 30273

You don't need the extra curly braces; this should work fine:

if { [info exists HI] && $HI == 1 } { puts "Hello World" }

Upvotes: 5

triclosan
triclosan

Reputation: 5714

Try to [expr $HI == 1] instead of { $HI == 1 }

Upvotes: 1

Related Questions