5

In my perl script, I used if ($a == undef) condition, I thought it is the same as if (not defined $a), where $a is a string as read from a csv file. However, I noticed that several string values ("", " ", "0", "-0", "+0", "@", "a", and many other spaces and special characters) are defined but also undef. If undef is only for numeric values, it should pass "0", "+0", and "-0". Can anyone explain? I understand now that I should not use if ($a == undef) to replace if (not defined $a).

My testing code is:

@a_array = ("-1", "-0", "0", "+0", "1", "", " ", "@", "a", "\$", "-");
undef $a;
test_a();

foreach $a (@a_array) {
    $len_a = length($a);
    test_a();
}

sub test_a {
    if (defined $a) { print "a = $a is defined;  "} else {print "a = $a not defined; "}; 
    if ($a == undef) { print "a = $a (== undef);  "} else {print "a = $a (!= undef); "}; 
    if (length($a) > 0){ print "length of a is $len_a > 0 \n"} else {print "length of a is $len_a !> 0 \n"};
}
zdim
  • 64,580
  • 5
  • 52
  • 81
Douglas
  • 71
  • 1
  • 1
    Always `use strict; use warnings;`. Don't use [$a](https://perldoc.pl/variables/$a) as an example, consider `$x` and `$y`. – Grinnz Feb 06 '20 at 22:43
  • 1
    Always pass to subs _everything_ that they need, never rely on a sub "seeing" values from outside scope. So that `test_a` sub should take `$a` as an argument (just named better). – zdim Feb 06 '20 at 23:37
  • Documentation for [defined](https://perldoc.perl.org/functions/defined.html) gives good explanation of it's purpose. **undef** is separate entity and different from 0, '' or anything else. – Polar Bear Feb 07 '20 at 00:28

1 Answers1

7

Perl has two equality operators: == and eq. == tests if the numeric form of each value is numerically equal. eq tests if the string form of each value is lexicographically equal. undef is not a string or a number, and if used as a string it is equivalent to the empty string, if used as a number it is equivalent to 0 (as is the empty string, and any string that doesn't start with something that looks like a number). You usually get warnings when this happens.

To test for undef, no equivalence test should be involved: use the defined function. Only if it is defined can it have a meaningful string or number value, and you can do subsequent tests.

The length function returns undef when passed undef, so if you want to know if a scalar is both defined and not length 0, you only need one boolean check: if (length $x). 0 and undef are both false results. Note that before Perl 5.12 this would cause a warning, as length undef attempted to use undef as a string, like eq does.

Grinnz
  • 9,093
  • 11
  • 18
  • Grinnz, thank you for the clarifications. Now I understand my main confusions: 1) between eq and ==; 2) between defined and undef. I also noticed that eq and == are exchangeable between string and numeric, except for undef. Another point is undef $x or $x = undef work for both string and numeric when assigning (clearing) values, but only works for numeric comparison. Any corrections/comments on my observations? – Douglas Feb 07 '20 at 16:49
  • 1
    @Douglas Sorry I don't really follow what you are trying to say. `eq` is always a string comparison, `==` is always a numeric comparison, there are values which are different strings but the same number, and vice versa. `undef` has nothing to do with comparisons of either kind, and is string-equal to the empty string and numeric-equal to 0. – Grinnz Feb 07 '20 at 16:55
  • Thank you again. I understand the problem now. My last comment do not make much sense since I used == and undef incorrectly (though it worked partially). – Douglas Feb 07 '20 at 17:03