The reference page for if can be found at http://purl.org/tcl/home/man/tcl8.5/TclCmd/if.htm if is a part of the Tcl core distribution. The standard way of performing a test and executing a script depending on the result. I happen to believe that the following [[if]] commands are good style, and this is because the styles minimise the number of backslashes (a problem if you insist on putting open braces at the start of a line out of some belief that Tcl has to look like C) and maximise the comprehensibility and readability at a local level (where you need an otherwise clause, always mark it with ''else'', and where the start of the then clause is not on the same line as the condition that guards it, always mark it with ''then'' - it is better to have a multi-line condition than it is to have one monster that wraps round several times.) '''DKF''' ---- # Standard simple if if {some condition} { # Note that the open-brace for the body is on the same line # as the if-command and condition. some conditionally executed script... } # Standard simple if with else clause if {some condition} { some conditionally executed script. } else { some script to execute if the condition isn't satisfied. } # Standard multi-test if if {first condition} { thing to do if the first condition succeeds } elseif {second condition} { thing to do if the first fails, but the second condition succeeds } else { what to do if none of the conditions match - this one is optional, but typically good practice to anticipate unexpected responses } # Handling complex (i.e. long) conditions if { this condition stretches over multiple lines } then { thing to do if the condition succeeds } ---- If you want to put the test and its corresponding (true) script on one line, and then have a large ''else'' spread out over several lines, you need to add a line-continuation backslash to that first line or Tcl consider the ''if'' complete and throw an error when it tries to run ''else'' as a command. Example: if {condition} {script} \ else { longer script } -CJU ---- Sample of boolean operators: set a 1 set b "stuff" if { $a == 1 || [string equal $b "nonsense" ] } { puts "found" } This demonstrates that one can test two (or more) expressions within the if {} expr1 . Note that in the second test, a Tcl command is executed and the result is tested for true or false. In both cases, as soon as the entire if expr1 can be determined true or false, processing stops. This is sometimes called 'short circuiting'. The good news is that it permits you to write things like: if a particular variable exists && a tcl command called using that function (variable) returns true do something special else we get here because the particular variable didn't exist. The ''bad'' news, as such, is that you have to be certain that you use the right boolean connector between the parts. The && requires that all parts of the if expr1 are true. The || requires only that one of them be true. ---- '''Intuitive logical operators''': You can use "and" for && and "or" for || if you use this preprocessor (accepts arguments like real [if], but preprocessing works so far only on the first condition): proc If {cond args} { regsub -all " and " $cond {\&\&} cond regsub -all " or " $cond {||} cond uplevel 1 if [list $cond] $args } ;#RS ---- In Tcl, [if] is a function, not just a control construct. Its result is that of the ''then'' or ''else'' clause, whichever executes. set y [if {$x} {list a} {list b}] ''$y'' will be "a" if ''$x'' evaluates to true, or "b" if ''$x'' evaluates to false. [expr]'s ?: operator does similar things. set y [expr {"foo"=="bar" ? "yes" : "no"}] - SCT & [RS] [LV] Just for completeness sake ====== % set x 0 0 % set y [if {$x} {list a}] % puts $y % ====== So, if returns an empty string if the body of the if does not execute. [AMG]: Be careful about using [list] for this purpose, because under some circumstances it must change its argument in order to produce a valid single-element list. [[list a]] may return "a", but [[list "a b"]] returns "{a b}" (it added the braces to the result). See my comment on the [return] page for safer ways to do this. I suggest using single-argument [lindex]; so basically replace "list" with "lindex" in the above code. ---- Why do if expressions use curly brackets? Dollar signs and square brackets are processed, obviously, and everything appears to work a lot like a quoted string. What gives? Just sugar? Admittedly, a lot of coders would be scared off by quoted conditionals, but I'm curious. '''FW''' [RS]: Curly braces are used to group their contents into one "word" without first-round evaluation. The contents will be evaluated unchanged by [expr], which is optimized in speed, e.g. for accesses to variables. On the other hand, it does not accept all conditions that will be accepted as pure strings (operators in variables, "dot cast"...) Especially for string constants, bracing is important to prevent parsing away quote signs. You can omit braces if the condition is one "word" already (i.e. does not contain whitespace). The first three are equivalent (though the first two may be slower): if $foo==1 {puts YES} ;#(1) if "$foo == 1" {puts YES} ;#(2) if {$foo == 1} {puts YES} ;#(3) if ""=="" {puts YES} ;#(4) ERROR: extra characters after close-quote So: you may do without curlies around [if] conditions, but they are recommended and sometimes required - not by [if], but by [the Tcl way]. [FW]: Ah, the ignorance of youth. Reading back on that is funny. I was thinking of conditionals in general, but I didn't know the general way to refer to it or realize it's the same thing as expr. ---- [LV] asks: does the evaluation of the if ''expr1'' differ from an invocation of the [expr] command? If so, in what ways? [RS]: I think seen from Tcl, they behave similarly - not sure about the implementation in the byte code compiler. But there is a difference in [for], whose second arg is also an [expr]-like condition: for {set x $from} {[expr $from $op $to]} {... If you want to retrieve operators from variables, you have to write an explicit, unbraced [expr], which is evaluated as wanted, and returns 0 or 1, which is then evaluated by [for]'s invocation of [expr]-like code... [rmax]: The additional [expr] can be avoided. You just have to make sure, that the operator (but nothing else) gets substituted before [for]'s second argument sees it: for {set x $from} "\$from $op \$to" {... A discussion of when in an if to use == vs using some other way of comparing two variables needs to be made either here or on its own page [string compare ...]. ''[DKF]:'' They use the same parser and bytecode generator. Main difference is that [expr] will concatenate its arguments before parsing, but '''if''' requires a single argument. ---- [Andreas Leitgeb] pointed out on [the comp.lang.tcl newsgroup] (2002-08-07) that if 1 $cmd is clearly faster then eval $cmd See [Many ways to eval] for the ensuing discussion. ---- [RJM]: can anybody explain why string comparisons in [if] using '''==''' or '''eq''' fail when one or both strings are constants? For example if {$a eq abc} ... The interpreter reports "variable references require preceding $". I'd expect to use quoting only when there are whitespaces in the string. Indeed I need quoting the constant string here. [RS]: The [little language] of expressions (used in [if], [for], [while], [expr]) is not fully the same as Tcl. The difference here is that string constants have to be explicitly grouped with "" or {}, which is not necessary in Tcl itself. Other differences are: * operators cannot be substituted from variables * functions are called like f($x,$y) instead of [[f $x $y]] * whitespace between operands and operators is not required ---- [LV] Starting in Tcl 8.5 , note that a new [expr] comparison becomes available for if : if {$pattern in [list case1 case2 case3 case4]} { ... } gives you the functionality of [lsearch] -exact while if {$pattern ni [list case1 case2 case3 case4]} { ... } gives you the negative version (pattern is not in the supplied case list). ---- [AMG]: I find it interesting to compare the way different languages spell "else if". Let's see... &| '''[C]''' | `else if` |& &| '''[Fortran]''' | `elseif`, with spaces anywhere you please |& &| '''[Tcl]''' | `elseif` |& &| '''[Perl]''', '''[Ada]''' | `elsif` |& &| '''[C] preprocessor''' | `#elif` |& &| '''[Python]''', '''[bash]''' | `elif` |& ---- [AMG]: [[if]] has two [noise words]: "then" and "else". Do any other core commands have such noise words? I'm not entirely clear on why "elseif" is mandatory whereas "then" and "else" are optional. If all three words are deleted from if's [little language], it would be possible to use parity to determine which arguments are conditions and which are code. The odd-numbered arguments (first, third, etc.) are conditions, the even-numbered arguments are code to run when the preceding condition is true, and if there's an odd number of total arguments, the last one is code to run when all the conditions are false. There must be at least two arguments. ====== if a b ;# if {a} then {b} if a b c ;# if {a} then {b} else {c} if a b c d ;# if {a} then {b} elseif {c} then {d} if a b c d e ;# if {a} then {b} elseif {c} then {d} else {e} ====== The only reason I can think of to require "elseif" is to help identify "parity errors" caused by an omitted or extra word. In the above example, see how "c" is a script on the second line and a conditional on the third and fourth lines? Because "elseif" is required, accidentally deleting the last argument won't convert the second-to-last argument from a conditional to a script, but instead will result in an [error]. I'm not sure that was the rationale for requiring it, because if it was, why isn't "else" required too? Hysterical raisins, perhaps? Don't get me wrong, I'm not complaining, and I'm not proposing any changes. I never omit the "else", so I don't mind the fact that "elseif" is required. ---- See also: * [expr problems with int] * [If we had no if] * [if 0 {] ---- !!!!!! %| [Category Command] | [Category Control Structure] |% [Tcl syntax help] [Arts and crafts of Tcl-Tk programming] !!!!!!