Side effects of overloading quotes ""

K

Koszalek Opalek

Hello,

I overloaded the quotes '""' in my class by using
use overload ('""' => \&getDesc);

I was hoping it will allow me to write
print ("Hello from object $obj.\n");
instead of
print ("Hello from object " . $obj->getDesc() . ".\n");

Well, it works that way but there are side effects that break my class
completely.


Problem 1)

Before overloading
if ($obj)
is true, if $obj is a reference to any object of class Obj.
If the reference is undef, $obj is false.
After overloading "", $obj is also false if getDesc() happens to
return an empty string! That's not what I wanted. If I did, I could
use
if ("$obj")


Problem 2)

Before overloading I could compare object references
if ($obj1 == $obj2)
and check if they point to the same location/object. I can no
longer do that once the '""' operator has been overloaded.

Operation "==": no method found,
left argument in overloaded package Obj,
right argument in overloaded package Obj at ./a.pl
line 38.

I can use eq instead of == if I also add falllback => 1 to the
overload pragma but that string-compares $obj1->dummy()
with $obj2->dummy() instead of object references. Again, if
I wanted to compare the string representation I could do
if ("$obj1" eq "$obj2")

Am I doing sth wrong or miss the point completely? Or is this
overload module broken beyond repair?

I enclose a short listing that demonstrates my point.
Uncomment one of the #use clauses to see how it breaks
things. Any help will be appreciated.



#!/usr/bin/perl
use strict;
use warnings;


{
package Obj;
#use overload ('""' => \&getDesc);
#use overload ('""' => \&getDesc, fallback => 1);


sub new ()
{
my $class = shift;
my $self = {};

bless $self, $class;
}

sub getDesc ()
{
return "";
};

};

my $obj1 = Obj->new();
my $obj2 = Obj->new();

### PROBLEM 1 ###
if ($obj1) {
print "true\n";
} else {
print "false\n";
};

### PROBLEM 2 ###
if ($obj1 == $obj2) {
print "same references\n";
} else {
print "different references\n";
};

__END__

Koszalek
 
A

A. Sinan Unur

I overloaded the quotes '""' in my class by using
use overload ('""' => \&getDesc);

I was hoping it will allow me to write
print ("Hello from object $obj.\n");
instead of
print ("Hello from object " . $obj->getDesc() . ".\n");

Well, it works that way but there are side effects that break my class
completely.

perldoc overload mentions:

* *Boolean, string and numeric conversion*
'bool', '""', '0+',

If one or two of these operations are not overloaded, the remaining
ones can be used instead. "bool" is used in the flow control
operators (like "while") and for the ternary "?:" operation. These
functions can return any arbitrary Perl value. If the corresponding
operation for this value is overloaded too, that operation will be
called again with this value.

As a special case if the overload returns the object itself then it
will be used directly. An overloaded conversion returning the
object is probably a bug, because you're likely to get something
that looks like "YourPackage=HASH(0x8172b34)".
Problem 1)

Before overloading
if ($obj)
is true, if $obj is a reference to any object of class Obj.
If the reference is undef, $obj is false.
After overloading "", $obj is also false if getDesc() happens to
return an empty string! That's not what I wanted. If I did, I could
use
if ("$obj")

Well, then, overload bool as well.
Problem 2)

Before overloading I could compare object references
if ($obj1 == $obj2)
and check if they point to the same location/object. I can no
longer do that once the '""' operator has been overloaded.

Again, overload 0+.
#!/usr/bin/perl
use strict;
use warnings;


{
package Obj;
#use overload ('""' => \&getDesc);
#use overload ('""' => \&getDesc, fallback => 1);

Don't comment out code in your posting. That makes it hard to figure out
exactly what code you ran.
sub new ()

Don't specify prototypes for methods: They have no effect and their use
is misleading. All this time, I have not found a good reason to use
prototypes in my code.

sub getDesc ()

Ditto for prototypes.
{
return "";
};

};

my $obj1 = Obj->new();
my $obj2 = Obj->new();

### PROBLEM 1 ###
if ($obj1) {
print "true\n";
} else {
print "false\n";
};

### PROBLEM 2 ###
if ($obj1 == $obj2) {
print "same references\n";
} else {
print "different references\n";
};

The solution to Problem 1 is to implement boolean conversion. The
solution to Problem 2 is also found in perldoc overload:

Public functions
Package "overload.pm" provides the following public functions:

overload::StrVal(arg)
Gives string value of "arg" as in absence of stringify overloading.
If you are using this to get the address of a reference (useful for
checking if two references point to the same thing) then you may be
better off using "Scalar::Util::refaddr()", which is faster.


Thus, you should also implement the equality operator.

So, here is a reworked example. I did change method names to my liking:

#!/usr/bin/perl
use strict;
use warnings;

package Obj;

use Scalar::Util qw( refaddr );

use overload
q{""} => \&to_string,
'bool' => \&to_bool,
q{0+} => \&to_val,
q{==} => \&is_identical,
;

sub new { bless {} => shift }

sub to_string { q{} }

sub to_bool { defined shift }

sub to_val { refaddr shift }

sub is_identical { refaddr shift == refaddr shift }

package main;

my $obj1 = Obj->new;
my $obj2 = Obj->new;

### PROBLEM 1 ###

print( $obj1 ? "true\n" : "false\n" );

### PROBLEM 2 ###

print( $obj1 == $obj2 ? "same\n" : "different\n" );

__END__
 
K

Koszalek Opalek

Don't comment out code in your posting. That makes it hard to figure out
exactly what code you ran.
Ok.
Don't specify prototypes for methods:
Sure.

So, here is a reworked example. I did change method names to my liking:

#!/usr/bin/perl
use strict;
use warnings;

package Obj;

use Scalar::Util qw( refaddr );

use overload
q{""} => \&to_string,
'bool' => \&to_bool,
q{0+} => \&to_val,
q{==} => \&is_identical,
;

sub new { bless {} => shift }

sub to_string { q{} }

sub to_bool { defined shift }

sub to_val { refaddr shift }

sub is_identical { refaddr shift == refaddr shift }

package main;

my $obj1 = Obj->new;
my $obj2 = Obj->new;

### PROBLEM 1 ###

print( $obj1 ? "true\n" : "false\n" );

### PROBLEM 2 ###

print( $obj1 == $obj2 ? "same\n" : "different\n" );

__END__


Thank you.
That works beautifully.

A.

 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top