Skip to content
VLSI Mentor

Tcl Part I · Module 4 · Operators and Expressions

The Conditional Operator

This operator picks one of two values based on a condition, inside an expression. It is the only operator in Tcl that takes three operands, and it fills a real gap: there are places where you need a value chosen on the spot and cannot stop to run a multi-line command. It is also easy to overuse. This chapter covers what it does, proves that only the chosen branch is evaluated, and gives a clear rule for when a plain if command says the same thing better.

Foundation10 min readTclPart IOperatorsConditionalReadability

Part I · Module 4 · Chapter 4.7 · The Conditional Operator

1. The Shape

Azvya Education Pvt. Ltd.VLSI Mentor
basic.tcl
set count 1
puts "1 [expr {$count == 1 ? "item" : "items"}]"

set count 3
puts "3 [expr {$count == 1 ? "item" : "items"}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1 item
3 items

Read it as: condition ? value if true : value if false.

The condition is read as a truth value, with the rules from Chapter 3.6 — so anything not on the accepted list is an error, not false.

2. Why It Earns Its Place

That singular-and-plural case is the best argument for the operator. The alternative is three lines and a variable to produce one word:

Azvya Education Pvt. Ltd.VLSI Mentor
the-long-way.tcl
set count 3

if {$count == 1} {
    set noun "item"
} else {
    set noun "items"
}
puts "$count $noun"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3 items

Both are correct. The first version keeps the choice where the value is used; the second introduces a variable whose only job is to carry a word to the next line.

3. Only One Branch Is Evaluated

Like && and || in Chapter 4.5, this operator does not evaluate what it does not need. The same technique proves it:

Azvya Education Pvt. Ltd.VLSI Mentor
one-branch.tcl
proc noisy {which} {
    puts "    (evaluated $which)"
    return $which
}

puts "result: [expr {1 ? [noisy TRUE] : [noisy FALSE]}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
    (evaluated TRUE)
result: TRUE

One message, not two. The false branch was never run.

That matters when a branch would be expensive or would fail:

Azvya Education Pvt. Ltd.VLSI Mentor
protective.tcl
set count 0
set total 50

puts [expr {$count == 0 ? "no data" : $total / $count}]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
no data

The division by zero never happened, because that branch was not selected.

4. Nesting

?: associates to the right — Chapter 4.2 §4 — which is what makes a chain read sensibly:

Azvya Education Pvt. Ltd.VLSI Mentor
nesting.tcl
foreach n {-5 0 7} {
    puts "$n is [expr {$n < 0 ? "negative" : $n == 0 ? "zero" : "positive"}]"
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-5 is negative
0 is zero
7 is positive

Each : carries the rest of the chain, so it reads top to bottom like a list of cases.

5. Common Uses

Azvya Education Pvt. Ltd.VLSI Mentor
uses.tcl
set errors 0
set verbose 1
set name ""

puts "status:  [expr {$errors == 0 ? "PASS" : "FAIL"}]"
puts "level:   [expr {$verbose ? "detailed" : "summary"}]"
puts "display: [expr {$name eq "" ? "(unnamed)" : $name}]"
puts "clamped: [expr {$errors > 100 ? 100 : $errors}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status:  PASS
level:   detailed
display: (unnamed)
clamped: 0

All four pick a value. That is the pattern the operator is for.

The third line is the nearest Tcl has to a default-value idiom, since Chapter 4.5 §6 showed that || returns 1 or 0 rather than an operand.

6. When to Use if Instead

The rule is not about length:

?: produces a value. if runs code.

Use ?: when you need one of two values in the middle of something else. Use if when you want one of two actions to happen.

Azvya Education Pvt. Ltd.VLSI Mentor
wrong-tool.tcl
set errors 2

expr {$errors > 0 ? [puts "there were errors"] : [puts "clean"]}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
there were errors

That works, and it is the wrong tool. Nothing wanted the value; the goal was to print something. An if says that directly.

You wantUse
one of two values, used immediately?:
one of two values, assigned to a variableeither; ?: is shorter
one of two actions to happenif
more than two casesif/elseif or switch
a branch that needs several linesif
a branch that needs a commentif

7. Readability

Two habits keep it readable.

Keep the branches short and similar. If the two values are long or of different kinds, the line stops being scannable:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set label [expr {$ok ? "pass" : "fail"}]

Parenthesise a complex condition. ?: is the loosest operator in the table, so it does not strictly need them — but a reader should not have to confirm that:

Azvya Education Pvt. Ltd.VLSI Mentor
parens.tcl
set a 5
set b 10

puts [expr {($a > 0 && $b > 0) ? "both positive" : "not both"}]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
both positive

8. Common Mistakes

Using it for actions. §6. Use if.

Chaining more than two conditions. §4. Use switch.

Expecting both branches to run. Only the selected one is evaluated. §3.

Forgetting the condition must be a truth value. expr {"maybe" ? 1 : 0} is an error — Chapter 3.6 §4.

Writing a long expression in one branch. Compute it first and name it.

9. Exercises

Exercise 1 — singular and plural. Write one puts that prints 1 file or 4 files correctly, driven by a variable.

Exercise 2 — prove the skip. Write the §3 noisy test yourself and confirm only one message appears. Then flip the condition to 0 and confirm the other branch runs instead.

Exercise 3 — a protective branch. Write an expression that gives the average of $total over $count, or the text n/a when count is zero. Confirm it does not error for count equal to 0.

Exercise 4 — chain three. Classify a number as low, medium or high using a nested conditional. Then rewrite it with if/elseif, and say which you would keep.

Exercise 5 — pick the tool. For each, say ?: or if: choosing a filename suffix; printing a warning when a count is high; clamping a value to a maximum; running a cleanup step only on failure.

Exercise 6 — the default idiom. Given a variable that may be an empty string, produce either its value or the text (none). Then explain why expr {$name || "(none)"} does not work.

10. Remember

  • The shape is condition ? value_if_true : value_if_false, inside expr.
  • It produces a value; if runs code. That is how to choose.
  • Only the selected branch is evaluated, so the other one may safely be expensive or invalid.
  • It associates to the right, which makes a two-level chain read top to bottom.
  • Two levels is the practical limit. Beyond that use switch or if/elseif.
  • The condition must be a valid truth value, or it is an error.
  • Parenthesise a complex condition, even though precedence does not require it.
  • It is the closest thing Tcl has to a default-value idiom, because || returns 1 or 0.

Next: the functions that live inside expressions.

Where this fits

Part of the Tcl curriculum.