Skip to content
VLSI Mentor

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 asEqualNot equal
numbers==!=
texteqne

$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

Azvya Education Pvt. Ltd.VLSI Mentor
name-check.pl
use strict;
use warnings;

my $name = "Ravi";

print "ok\n"    if $name eq "Ravi";
print "wrong\n" if $name == "Asha";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDOUT
ok
wrong
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
Argument "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.

Azvya Education Pvt. Ltd.VLSI Mentor
numbers-as-text.pl
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";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
10 == 10.0   : equal
'10' eq '10.0': differ
'007' == '7'  : equal
'007' eq '7'  : differ
'1e3' == 1000 : equal
'1e3' eq '1000': differ

Three 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:

  • 10 and 10.0 — the same value written with and without a decimal point. Any tool that formats a number has made a choice here.
  • 007 and 7 — zero padding. Test indices, channel numbers, instance numbers and die coordinates are routinely padded so that they sort properly in a filename.
  • 1e3 and 1000 — 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

A fork with five blocks. At the middle left sit the two scalars being compared, holding the text Ravi and the text Asha. Two paths lead from them. The upper path runs right: the double-equals operator asks both operands for a numeric reading, which turns each non-numeric name into zero; the result is that zero equals zero, so the comparison reports TRUE and warns twice on standard error. The lower path runs right as well: the eq operator compares the two character sequences directly, finds that R-a-v-i is not A-s-h-a, and reports FALSE with no warning. The same two inputs therefore produce opposite verdicts depending only on which operator was written.Two scalars"Ravi" and "Asha" — 2.6== asks for numbersboth names read as 0 — 2.130 == 0 is TRUEplus two warnings on STDERReq comparescharactersR-a-v-i against A-s-h-aFALSEno warning — nothing wasoddwritten ==written eq12
Both paths start from the same two scalars and neither path is wrong. The top path asks a numeric question and gets a numeric answer; the bottom path asks a textual one. The defect in Section 2 is not that `==` malfunctioned — it is that a numeric question was asked about two names.

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 isExamplesUse
a quantitycounts, cycles, slack, voltage, a parsed index== !=
an identifier or labeltest name, block name, status word, tool nameeq ne
a quantity you must match exactly as writtena checksum, a revision string, a padded ID treated as a labeleq 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:

Azvya Education Pvt. Ltd.VLSI Mentor
choose.pl
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";
}
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
status compared as text: matched
count compared as a number: matched

Both 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:

Azvya Education Pvt. Ltd.VLSI Mentor
negation.pl
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;
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDOUT
not icc2 (text)
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
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_word says eq.
  • Treat the isn't numeric warning 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. eq and ne compare characters.
  • == on two non-numeric strings is true, because both numify to 0. 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.
  • eq is not the safe choice. 10 is not eq 10.0; 007 is not eq 7; 1e3 is not eq 1000 — 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 warnings is what makes this visible. isn't numeric in numeric eq (==) names the operator and the line; use strict says 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.