Skip to content
VLSI Mentor

Tcl Part I · Module 4 · Operators and Expressions

eq and ne: Comparing Strings on Purpose

The previous chapter established the problem: == asks a numeric question or a text question depending on what the data happens to look like, and nothing in the source says which. This chapter is the answer, and it is short. Tcl has two operators that always compare text and never change their minds. Once you have them, every comparison you write can say exactly which question it is asking — which turns a line that a reviewer has to think about into one they can simply read.

Foundation11 min readTclPart IOperatorsComparisonStrings

Part I · Module 4 · Chapter 4.4 · eq and ne: Comparing Strings on Purpose

1. The Two Operators

Azvya Education Pvt. Ltd.VLSI Mentor
basic.tcl
puts "\"abc\" eq \"abc\"  = [expr {"abc" eq "abc"}]"
puts "\"abc\" eq \"abd\"  = [expr {"abc" eq "abd"}]"
puts "\"abc\" ne \"abd\"  = [expr {"abc" ne "abd"}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
"abc" eq "abc"  = 1
"abc" eq "abd"  = 0
"abc" ne "abd"  = 1

eq is equal-as-text. ne is not-equal-as-text. That is the whole mechanism.

2. They Never Change Their Minds

This is the entire point. eq compares characters, always, regardless of what the operands look like:

Azvya Education Pvt. Ltd.VLSI Mentor
never-switches.tcl
puts "1 eq 1.0      = [expr {1 eq 1.0}]"
puts "100 eq 100    = [expr {100 eq 100}]"
puts "\"abc\" eq \"abc\" = [expr {"abc" eq "abc"}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1 eq 1.0      = 0
100 eq 100    = 1
"abc" eq "abc" = 1

1 eq 1.0 is false, because the characters differ. That is not a limitation — it is the guarantee. You know what the operator will do before you know what the data holds.

3. Side by Side

Azvya Education Pvt. Ltd.VLSI Mentor
compare.tcl
foreach pair {{1 1.0} {1e2 100} {" 5" "5"} {0x10 16} {abc abc}} {
    lassign $pair a b
    puts [format "%-6s vs %-6s   ==: %s   eq: %s" $a $b \
        [expr {$a == $b}] [expr {$a eq $b}]]
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1      vs 1.0      ==: 1   eq: 0
1e2    vs 100      ==: 1   eq: 0
 5     vs 5        ==: 1   eq: 0
0x10   vs 16       ==: 1   eq: 0
abc    vs abc      ==: 1   eq: 1

Four of the five disagree. In every case == said "the same number" and eq said "different characters", and both were telling the truth about different questions.

The last row agrees because abc is not numeric, so == fell back to a text comparison — Chapter 4.3 §3.

4. Why a Reader Can Trust eq

Return to the procedure from the previous chapter, written both ways:

Azvya Education Pvt. Ltd.VLSI Mentor
two-procs.tcl
proc same_number {a b} { return [expr {$a == $b}] }
proc same_text   {a b} { return [expr {$a eq $b}] }

foreach pair {{10 10.0} {abc abc} {007 7} {v1.0 v1.00}} {
    lassign $pair a b
    puts [format "%-6s %-6s  same_number:%s  same_text:%s" \
        $a $b [same_number $a $b] [same_text $a $b]]
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
10     10.0    same_number:1  same_text:0
abc    abc     same_number:1  same_text:1
007    7       same_number:1  same_text:1
v1.0   v1.00   same_number:0  same_text:0

same_text is predictable from its name on every row. same_number is not — it answered a numeric question on rows one and three and a text question on rows two and four.

Look at row three. 007 and 7: same_number says yes, and same_text also says yes — but for a reason worth understanding, which is the next section.

5. The Compound Trap

Row three deserves its own look, because two of this track's traps stack there.

Azvya Education Pvt. Ltd.VLSI Mentor
octal-compound.tcl
set code "0010"

puts "\$code == 10  = [expr {$code == 10}]"
puts "\$code == 8   = [expr {$code == 8}]"
puts "\$code eq \"10\" = [expr {$code eq "10"}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$code == 10  = 0
$code == 8   = 1
$code eq "10" = 1

Read that carefully, because the first line is probably not what you expected.

"0010" compared numerically is 8, not 10 — a leading zero means octal, which is Chapter 3.5 §6. So $code == 10 is false, and $code == 8 is true.

Two independent surprises in one comparison: the operator chose a numeric reading, and the numeric reading chose base 8.

6. The Decision Rule

One question:

Am I asking about a quantity, or about characters?

  • A quantity — a count, a size, a measurement, a threshold → == and !=.
  • Characters — a name, a code, a status, a mode, an identifier, a version → eq and ne.
You are comparingUse
counts, sizes, totals== !=
a value against a numeric threshold== != < >
names, modes, statuseseq ne
identifiers and codes, especially zero-paddedeq ne
version stringseq ne
anything from a file whose shape you do not controleq ne
measured real numbersneither — Chapter 4.10

When in doubt about non-numeric data, eq is the safer default, because its answer does not depend on what the input happens to contain.

7. A Worked Example

Azvya Education Pvt. Ltd.VLSI Mentor
modes.tcl
set mode "fast"

if {$mode eq "fast"} {
    puts "running the quick path"
} elseif {$mode eq "careful"} {
    puts "running all checks"
} else {
    puts "unknown mode: $mode"
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
running the quick path

Every comparison here is about characters, so every one is eq. If a later release adds a mode called 2, nothing about these lines changes meaning — which is exactly the property == could not offer.

Chapter 4.9 shows a neater way to write the membership version of this, and switch in Module 8 is better again once there are several cases.

8. There Is Also a Command

For completeness, since you will meet it: string equal does the same job at command level, and adds options eq does not have.

Azvya Education Pvt. Ltd.VLSI Mentor
string-equal.tcl
puts "string equal:          [string equal "abc" "abc"]"
puts "ignoring case:         [string equal -nocase "ABC" "abc"]"
puts "first 2 characters:    [string equal -length 2 "abcdef" "abxxxx"]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
string equal:          1
ignoring case:         1
first 2 characters:    1

Inside an expression, eq is shorter and reads better. Reach for string equal when you need -nocase or -length. Module 5 covers it properly.

9. Common Mistakes

Using == on codes and identifiers. §5. Zero-padded ones are read as octal.

Thinking eq is slower or less precise. It is a direct character comparison and is the simpler operation.

Expecting 1 eq 1.0 to be true. It is false by design. §2.

Using eq on measured numbers. 10.0 eq 10 is false even when the quantity is identical. Use == for quantities.

Forgetting ne exists and writing ![expr {$a eq $b}]. Write $a ne $b.

10. Exercises

Exercise 1 — disagree on purpose. Find three pairs of values where == and eq give different answers. Explain each in terms of what the two operators compared.

Exercise 2 — the octal code. Set a variable to "0012". Predict == 12, == 10, and eq "0012" before running all three. Which surprised you, and which two chapters does it combine?

Exercise 3 — pick the operator. For each, choose == or eq and justify it in a few words: retry count against a limit; a filename against report.txt; a temperature against 20; a user-supplied mode against verbose; a part number against 00417.

Exercise 4 — break a working script. Write a comparison with == that is correct for the values alpha and beta, then supply values that make the same line answer a different kind of question. Then fix it with eq.

Exercise 5 — the version check. Write a test for whether a version string is exactly 2.10. Show that == gets it wrong for the input 2.1, and that eq does not.

Exercise 6 — ignore case. Compare YES and yes so they count as equal. Which tool from §8 did you need, and why will eq not do it?

11. Remember

  • eq and ne always compare text, whatever the operands look like.
  • That predictability is the point. The question does not change with the data.
  • 1 eq 1.0 is false — different characters, same number.
  • Ask: quantity, or characters? == for quantities, eq for everything else.
  • Codes and identifiers are characters. Zero-padded ones are read as octal by ==.
  • For non-numeric data, eq is the safer default.
  • string equal is the command form, with -nocase and -length.
  • Neither operator suits measured real numbers. Chapter 4.10.

Next: combining conditions, and the evaluation rule that makes a guard possible.

Where this fits

Part of the Tcl curriculum.