http://www.perlmonks.org?node_id=232919

waxmop has asked for the wisdom of the Perl Monks concerning the following question:

Why doesn't == test all objects? WHY?

Here's some perl mason code I've been wrestling with. I couldn't figure out what was the problem until I remembered that in perl, you gotta use 'eq' to compare strings.

<table> % foreach my $rec (@records) { % foreach my $k ( keys %ARGS ) { % if ( $ARGS{$k} ) {  <tr>   <td><% $rec->{$k} %></td><td><% $ARGS{$k} %></td> % if ( $ARGS{$k} eq $rec->{$k} ) {   <td>MATCH!</td> % }  </tr> % } % } % } </table>

Will this be changed in perl6? I really hope so. Python's == operator works great for all different sorts of objects. And ruby makes it super easy to overload every operator in the book. But not in perl! We gotta use a different comparison operator for different objects! GAHH!

Replies are listed 'Best First'.
Re: my least favorite perl feature
by Zaxo (Archbishop) on Feb 05, 2003 at 20:55 UTC

    Time to breathe in the Zen.

    Perl stringifies and numifies things at need. Scalars silently become strings for printing, numbers for arithmetic.

    When you choose between == and eq don't think of it as forced by the nature of the scalar. Think of it as choosing for yourself how the comparison will be done.

    After Compline,
    Zaxo

      After breathing some Zen, I still wish there was some sort of 'object equivalence testing operator' in Perl. I could use it to compare two hashes, or two arrays, or objects, or whatever, and it would give me a same/not-same response.

        Well, the question "when are two arrays the same" has never been answered in a way all people could agree on.

        Personally, I find the current behaviour of

        if (@array1 == @array2)
        very useful. I wouldn't want to miss it.

        Furthermore, you'd have a hard time convincing me that you need to do less work for redefining an operator than for defining a function. Why not create a function that compares two arrays?

        Lastly, perl6 will have a supermatching operator. It will do all kinds of different things, depending on the types of its operands. Perhaps your idea of comparing arrays is one of the possible options.

        Abigail

Re: my least favorite perl feature
by tall_man (Parson) on Feb 05, 2003 at 21:07 UTC
    What is "overloaded" by design in perl is two possible values for every scalar: a string or a number. The comparison operators let you choose which. Do you want to give up either lexical or numeric sorting by overloading "<=>"?

    By the way, if you "use warnings" perl will help you out, like so:

    Argument "bbb" isn't numeric in numeric eq (==) at ddd.pl line 4.

      I would "use warnings", but in mason, it just isn't useful. For example, here's the message I get back when I "use warnings":

      Mason error error in file: /usr/local/lib/perl5/5.6.0/Carp/Heavy.pm line 79: Bizarre copy of HASH in aassign context: ... 75: # them according to the format variables defined earlier in 76: # this file and join them onto the $sub sub-routine str +ing 77: if ($hargs) { 78: # we may trash some of the args so we take a copy 79: @a = @DB::args; # must get local copy of args 80: # don't print any more than $MaxArgNums 81: if ($MaxArgNums and @a > $MaxArgNums) { 82: # cap the length of $#a and set the last element to '.. +.' 83: $#a = $MaxArgNums; ... component stack: /orders_survey/search.html code stack: /usr/local/lib/perl5/5.6.0/Carp/Heavy.pm:79

      See what I mean?

        That's a bug in 5.6.0. Upgrading to 5.8 (or at least 5.6.1) ought to fix it.

Re: my least favorite perl feature
by Elian (Parson) on Feb 05, 2003 at 21:40 UTC
    Perl 6 will keep == as numeric comparison and eq as string comparison, though you'll be able to overload them if you want, though you can now.

    There'll also be more effective "are these two objects the same object" and "are these two objects functionally equivalent" comparisons, though I don't know that they'll get punctuation.

Re: my least favorite perl feature
by hding (Chaplain) on Feb 05, 2003 at 22:15 UTC

    Though this article deals with Lisp rather than Perl, the point is the same: equality (and its cousin copying) are rather difficult concepts, and it's rather impossible to get an operation involving them to automatically do the "right thing" all of the time, because there are many conflicting and incompatible yet individually perfectly valid notions of what the right thing is.

Re: my least favorite perl feature
by BrowserUk (Patriarch) on Feb 05, 2003 at 21:49 UTC

    How does Python handle the dofference/similarity here?

    print '100 is numerically ', 100 == $_ ? ' the same ' :' different, ', + 'and lexically ', 100 eq $_ ? ' the same ' : ' different', ' to ', + "$_", $/ for qw[100 100.0 1e2 .1e3 1000e-1] 100 is numerically the same and lexically the same to 100 100 is numerically the same and lexically different to 100.0 100 is numerically the same and lexically different to 1e2 100 is numerically the same and lexically different to .1e3 100 is numerically the same and lexically different to 1000e-1

    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

      I don't have a python interpreter to double check - but I'm pretty sure that python == would be true for all the pairs of numbers you give (since numbers are automatically converted to a common type in python comparisons.)

      <update>If they are numbers I mean. For strings only "100" == "100" returns true, all others false. If one a string and the other a number, always false.</update>

      For objects == is true in python if they are the same object (in perl refaddr($o1) == refaddr($o2).

      For full details see this bit of the python docs.

      is that python's == operator can be used to test different objects, like tuples, class objects, whatever.

        a) I'd still like to see the answer to the preceeding question as I have no knowledge of how Python would differeciate the examples I gave.

        b) Could you give a couple of examples of where you use == in Python where you cannot in Perl? Again partly for my interest, partly because it ia easier understand you meaning from concrete examples than nebulous statements.


        Examine what is said, not who speaks.

        The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Same number, different string [Re: my least favorite perl feature]
by bronto (Priest) on Feb 06, 2003 at 15:47 UTC

    Actually, your problem doesn't have a simple solution. Two equal strings surely have the same numerical values, but what about two different strings? According to perlnumber these different strings all have the same numerical value: 1, 0x1, 01, 0b00000001

    So, when $a eq $b says they are different, what would you do? I'll compare with == then! It's a simple or!. Gotcha! I am sorry, it's wrong: try to see what happens with ($a,$b) = qw(x y)...

    What then? Well, when they are stringwise different, you have to choose again if you want to make a numerical comparison or not. You could check (by means of a regexp, for example) if $a and $b look like a number. If they don't, they are different and that's the end of the game; if they both are numbers you can (finally) proceed with ==

    I had liked to find a better solution, but I think there isn't any.

    Ciao!
    --bronto


    The very nature of Perl to be like natural language--inconsistant and full of dwim and special cases--makes it impossible to know it all without simply memorizing the documentation (which is not complete or totally correct anyway).
    --John M. Dlugosz

      I don't think a simple solution was being asked for - just a solution ;-)

      Equality is a bit of a bugger since it can mean so many different things. Perl gives us string and number equality - but their are others. For example Common Lisp provides eq, eql, equal, =, string-equal and char-equal - which all do slightly different things.

      I miss "the same object" equals quite a bit in my coding (eq in Common Lisp). waxmop wants something like Common Lisp's equal.

Re: my least favorite perl feature
by Aristotle (Chancellor) on Feb 06, 2003 at 12:27 UTC
    It's pretty simple. You use eq for all cases, except for using == when you need a numeric comparison. That's pretty much it, for 99.99% of the time. How hard can that be?

    Makeshifts last the longest.

      Not hard obviously ;-) However, I do miss the ability to say succinctly whether two things are the same "object" or not - something like Common Lisp's eq, Pop-11's == or python's is.

      I admit Perl's eq works for this case 99% of the time, I don't like using it for identity checks because:

      • It's not explicit enough. I want to say "these two things are the same" not "these two things expressed as strings are the same"
      • Stringification has got to be more expensive than a direct comparison internally.
      • It can fail when you have overloading of eq or "". I don't like writing code that can fail, even if it is only a few edge cases :-)

      It's easy to write your own obviously - this does the job:

      #! /usr/bin/perl use strict; use warnings; use Scalar::Util qw(refaddr); sub same { ref($_[0]) && ref($_[1]) && refaddr($_[0]) == refaddr($_[1]) || refaddr(\$_[0]) == refaddr(\$_[1]); }; use Test::More 'no_plan'; our ($x, $y, $z) = (1,1); *z = *x; ok same($x, $x), 'x is x'; ok same(\$x, \$x), 'ref x is ref x'; ok !same($x, $y), 'x not y'; ok same($x, $z), 'x is z';

      But, in my opinion, something this basic should be in the base language... but I guess that's what perl6 is for :-)