Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 453
scozy Avatar asked May 01 '14 11:05

scozy


1 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.

like image 158
amon Avatar answered Oct 23 '22 11:10

amon