Perl Part I · Module 3 · Operators and Expressions
Numeric vs String Comparison: == vs eq
Perl has two equality operators and they are not interchangeable. Compare two different names with == and Perl reports that they are equal — not approximately, not oddly, but equal — because both read as zero when asked for a number, and zero equals zero. A filter built that way matches every input it sees. The reverse mistake is just as real: 10 and 10.0 are not eq, and neither are 007 and 7, which is a problem when a tool writes zero-padded identifiers. So this is not a chapter where one operator turns out to be the safe choice. It is a chapter about deciding what kind of thing you are comparing before you choose how to compare it, which is the single highest-value habit in Perl.
Foundation16 min readPerlPart IFundamentalsComparisonOperatorsDebugging
Part I · Module 3 · Chapter 3.5 · Numeric vs String Comparison: == vs eq
1. Two Operators for One Idea
Perl spells equality twice:
| Compare as | Equal | Not equal |
|---|---|---|
| numbers | == | != |
| text | eq | ne |
$a == $b asks are these the same quantity? $a eq $b asks are these the same sequence of characters? Those are different questions, and Perl makes you say which one you meant.
Most languages do not. In Python, == on two strings compares characters and on two numbers compares quantities, because the values carry their types and the operator can look. Perl cannot look: Chapter 2.6 established that a Perl scalar is not labelled "number" or "string", and Chapter 3.3 §4 showed the consequence — 10 . 4 is 104 and 10 + 4 is 14, because the operator decides how its operands are read.
Equality is that same rule, and it is where the rule stops being a curiosity.
2. The Expensive Case
use strict;
use warnings;
my $name = "Ravi";
print "ok\n" if $name eq "Ravi";
print "wrong\n" if $name == "Asha";ok
wrongArgument "Asha" isn't numeric in numeric eq (==) at name-check.pl line 7.
Argument "Ravi" isn't numeric in numeric eq (==) at name-check.pl line 7.Read line 7 again, and read what it printed.
$name holds "Ravi". The comparison asks whether "Ravi" is numerically equal to "Asha" — and Perl says yes.
Here is why, and it follows entirely from rules you already have. == wants numbers, so it asks both operands for a numeric reading. By Chapter 2.13, text with no leading number reads as 0. So "Ravi" becomes 0, "Asha" becomes 0, and 0 == 0 is true.
This is worse than a wrong answer. == reports that any two non-numeric strings are equal. Not these two particularly — all of them. A name filter written with == matches every name. A check for a specific tool version matches every version. A dispatch on a command string takes the first branch, always.
What did announce it was use warnings, twice, naming the line and both operands. That is Chapter 1.11's argument reduced to a single line of evidence: the diagnostic turned an invisible logic error into a message with a line number. Without use warnings this script prints ok and wrong and says nothing at all.
3. The Mirror Image
It would be convenient if the lesson were "use eq and stay safe". It is not, and believing it is substitutes one defect for another.
use strict;
use warnings;
print "10 == 10.0 : ", (10 == 10.0 ? "equal" : "differ"), "\n";
print "'10' eq '10.0': ", ("10" eq "10.0" ? "equal" : "differ"), "\n";
print "'007' == '7' : ", ("007" == "7" ? "equal" : "differ"), "\n";
print "'007' eq '7' : ", ("007" eq "7" ? "equal" : "differ"), "\n";
print "'1e3' == 1000 : ", ("1e3" == 1000 ? "equal" : "differ"), "\n";
print "'1e3' eq '1000': ", ("1e3" eq "1000" ? "equal" : "differ"), "\n";10 == 10.0 : equal
'10' eq '10.0': differ
'007' == '7' : equal
'007' eq '7' : differ
'1e3' == 1000 : equal
'1e3' eq '1000': differThree pairs, and in every one the two operators disagree. The numbers are the same quantity and different text, which is not a contradiction — it is the definition of the two operators working correctly.
Now notice what the three pairs are:
10and10.0— the same value written with and without a decimal point. Any tool that formats a number has made a choice here.007and7— zero padding. Test indices, channel numbers, instance numbers and die coordinates are routinely padded so that they sort properly in a filename.1e3and1000— scientific notation. Timing values, capacitances and delays come out of EDA tools in this form constantly.
All three are things you will actually read out of a log file. So eq on a number is not a theoretical hazard; it is the specific way a script fails when someone compares a parsed timing value against a threshold written the other way.
4. The Fork, Drawn
One pair of values, two operators, two incompatible verdicts:
The operator chooses the comparison, and the comparison chooses the answer
The two paths never meet. Nothing downstream can recover the right answer, because nothing downstream knows a question was asked incorrectly — it received a clean true or false.
5. Choosing Correctly
The rule is one sentence: choose the operator that matches the kind of thing the value is, not the kind of thing it looks like.
That distinction matters because everything read from outside your script arrives as text, as Chapter 2.5 established. A test count parsed out of a log is text that represents a number, and the kind of thing it is, is a number. Compare it with ==.
| The value is | Examples | Use |
|---|---|---|
| a quantity | counts, cycles, slack, voltage, a parsed index | == != |
| an identifier or label | test name, block name, status word, tool name | eq ne |
| a quantity you must match exactly as written | a checksum, a revision string, a padded ID treated as a label | eq ne |
The third row is the one that needs thought. 007 as a channel number is a quantity — == 7 is right. 007 as a key that must round-trip into a filename is a label — eq "007" is right. The value is identical; the question differs; and you are the only one who knows which you are asking.
Here is the practical version on data that has just been read in:
use strict;
use warnings;
my $status = "FAILED";
my $errors = "0";
if ($status eq "FAILED") {
print "status compared as text: matched\n";
}
if ($errors == 0) {
print "count compared as a number: matched\n";
}status compared as text: matched
count compared as a number: matchedBoth values are strings — $errors is the text "0", not the number — and the right operator for each is determined by what it means, not by how it was stored. $errors == 0 is correct precisely because "0" is a quantity written as text, and == is how you ask about quantities.
6. != and ne
The negations follow the same split and the same hazards:
use strict;
use warnings;
my $tool = "dc_shell";
print "not icc2 (text) \n" if $tool ne "icc2";
print "not icc2 (numeric)\n" if $tool != 0;not icc2 (text)Argument "dc_shell" isn't numeric in numeric ne (!=) at negation.pl line 7.The second condition was false: "dc_shell" numifies to 0, and 0 != 0 is not true, so the line did not print. Written as a tool check — "if the tool is not the default" — != would report that every non-numeric tool name is the default. Same mechanism, same silence, one more warning that you should read.
7. Why This Matters in Engineering Work
Three concrete shapes, all of which come from the same root.
A filter that matches everything. next if $test == "smoke"; in a loop over test names skips every test, because every name numifies to 0. The script runs, reports nothing to do, and exits cleanly. There is no output to be suspicious of.
A threshold compared as text. A slack value parsed as 1e-10 compared with eq "0.0000000001" never matches, even though the two are the same number. The script reports no violations, which is the answer everyone wants to hear.
A padded identifier compared as a number. die_007 and die_7 are different directories on disk. If the script that builds the path compares with ==, the two are the same and one overwrites the other's results. This one is not just a wrong report; it destroys data.
Two habits cover all three:
- Say what the value is, in a comment or a variable name, at the point you read it in.
my $error_count = ...tells the next reader — and you, three hundred lines later — that==is the operator for it.my $status_wordsayseq. - Treat the
isn't numericwarning as an error. It is not a style note. It means an operator asked for a numeric reading of something that is not a number, and in a comparison that almost always means the comparison is meaningless. Module 14 covers making warnings fatal so that this cannot be scrolled past.
8. Common Mistakes
Using == on names, statuses or any text. Every non-numeric string equals every other. The filter matches everything.
Using eq on numbers. 10 is not eq to 10.0, 007 is not eq to 7, and 1e3 is not eq to 1000.
Concluding that eq is the safe default. It is wrong exactly as often as ==, just on different data — and the data it is wrong on is the data EDA tools emit.
Ignoring isn't numeric in numeric eq (==). That warning is the bug, announced, with a line number.
Deciding by how the value is stored rather than what it means. A parsed count is text and is still a quantity. Compare it with ==.
Assuming use strict helps here. It does not. Both forms are perfectly legal code with correctly declared variables; only use warnings says anything.
9. Exercise
Exercise 1 — reproduce the alarming result. Run the §2 script. Confirm that wrong prints, record both warnings, and write one sentence explaining why two unrelated names compared equal.
Exercise 2 — scale the failure. Write a script with three names in a row — say "Ravi", "Asha", "Meera" — and for each one print whether it == "Ravi" and whether it eq "Ravi". Count how many of the three the == test claims are Ravi, and say what that would mean inside a filter.
Exercise 3 — the mirror image. Without running them, predict "3.0" == 3, "3.0" eq "3", "0010" == 10 and "0010" eq "10". Then run all four. For each, name the row of §5's table that tells you which operator was appropriate.
Exercise 4 — classify before comparing. For each value, say whether you would compare it with == or eq, and give the reason in one clause: (a) the number of failing tests parsed from a summary line; (b) the name of the tool that produced a log; (c) a wafer identifier like W007; (d) a setup slack in nanoseconds; (e) a run status word such as COMPLETED; (f) a zero-padded test index that is also used to build the output filename.
Exercise 5 — make the warning impossible to miss. Write a script that compares a name with ==, run it, and capture STDOUT and STDERR into two separate files. Confirm that the output file alone contains no evidence of the bug, and say in one sentence what that implies about a script whose STDERR is discarded in a batch flow.
10. Summary
- Perl has two equality operators because a scalar carries no type. The operator decides how its operands are read — the rule from Chapter 2.6 and Chapter 3.3 §4.
==and!=compare quantities.eqandnecompare characters.==on two non-numeric strings is true, because both numify to0. It does not match the wrong thing; it matches everything.- The failure mode is a filter that passes everything, which looks like working software far longer than a filter that passes nothing.
eqis not the safe choice.10is noteq10.0;007is noteq7;1e3is noteq1000— and all three forms come out of real tools.- Choose by what the value means, not how it is stored. Text parsed from a log can still be a quantity.
use warningsis what makes this visible.isn't numeric in numeric eq (==)names the operator and the line;use strictsays nothing.
Chapter 3.6 extends the same split to the ordering comparisons — < against lt and the rest — where the consequences are quieter but the rule is identical.
Where this fits
Part of the Perl curriculum.
