Why does `eq` not work when one argument has overloaded stringification?

I have realised (the hard way) that operator eq gives a fatal runtime error when one of the operand is an object with overloaded stringification.

Here is a minimal example:

my $test = MyTest->new('test');
print 'yes' if $test eq 'test';

package MyTest;

use overload '""' => sub { my $self = shift; return $self->{'str'} };

sub new {
    my ( $class, $str ) = @_;
    return bless { str => $str }, $class;
}

The result of running this is:

Operation "eq": no method found,
    left argument in overloaded package MyTest,
    right argument has no overloaded magic at ./test.pl line 7.

My expectation from reading perlop would be that string context is forced on both operands, firing the stringification method in $test, then the resulting strings are compared. Why doesn't it work? What is actually hapenning?

The context in which I had this problem was in a script that uses both autodie and Try::Tiny. In the try block, I die with some specific messages to be caught. But in the catch block, when I test for whether $_ eq "my specific message\n", this gives a runtime if $_ is an autodie::exception.

I know I will have to replace $_ eq "..." with !ref && $_ eq "...", but I would like to know why.

Answers


You only overloaded stringification, not string comparison. The overload pragma will however use the overloaded stringification for the string comparison if you specify the fallback => 1 parameter:

my $test = MyTest->new('test');
print 'yes' if $test eq 'test';

package MyTest;

use overload
    fallback => 1,
    '""' => sub { my $self = shift; return $self->{'str'} };

sub new {
    my ( $class, $str ) = @_;
    return bless { str => $str }, $class;
}

Details on why this works:

When handed an overloaded object, the eq operator will try to invoke the eq overload. We did not provide an overload, and we didn't provide a cmp overload from which eq could be autogenerated. Therefore, Perl will issue that error.

With fallback => 1 enabled, the error is suppressed and Perl will do what it would do anyway – coerce the arguments to strings (which invokes stringification overloading or other magic), and compare them.


Need Your Help

Rails on Windows is so slow (rails -v takes 4 seconds)

ruby-on-rails ruby windows windows-vista

I'm using rails Version 3.0.3 and ruby Version 1.9.2p136 (2010-12-15) on a Intel Core 2 Duo 2,6 Ghz with 4 GB Ram and Windows Vista Business SP2 with no other (heavy) applications running. I have a...