Class instances with 'use overload' in a tied hash

Class instances with 'use overload' in a tied hash

Post by Guy Bolton » Wed, 30 Mar 2005 01:36:09


Hi,

I'm relatively new to the OO-features of perl, so I may have made an
obvious mistake in the following code, in which case I apologise for
wasting the group's time. I have a value-type class (Foo in the
example below) which overloads the comparison operator. sort() then
successfully uses the comparison operator when sorting a list of
instances obtained from the values() of a hash. However, if the class
instances are used as the values in a _tied_ hash, the overloaded
operator is no longer called, _unless_ values() is called before
calling the sort() function.

Have I made a mistake? Or is this something I shouldn't even attempt
in perl?

Thanks in advance,

Guy.

---snip!---

#!/usr/bin/env perl

use strict;
use warnings FATAL => 'all';

{
package Foo;

sub new {
my $self = bless({}, shift());
$self->{val} = shift();
return $self;
}

sub compare {
my ($self, $other) = @_;
return $self->{val} cmp $other->{val};
}

use overload
'cmp' => sub {
print "operator cmp\n";
return compare(@_);
},
'""' => sub {
printf "operator \"\" -> %s (%s)\n",
$_[0]->{val}, join(' ', caller());
return val(@_);
};
}


{
package FooHash;

sub TIEHASH { bless {}, $_[0] }

sub STORE {
printf "STORE(%s)\n", $_[1];
$_[0]->{$_[1]} = $_[2];
}

sub FETCH {
printf "FETCH(%s)\n", $_[1];
return $_[0]->{$_[1]};
}

sub FIRSTKEY {
print "FIRSTKEY\n";
keys %{$_[0]};
return $_[0]->NEXTKEY();
}

sub NEXTKEY {
my @result = each %{$_[0]};
print "NEXTKEY\n";
return wantarray ? @result : scalar(@result) ? $result[0] : undef;
}

sub EXISTS {
printf "EXISTS(%s)\n";
exists $_[0]->{$_[1]};
}

sub DELETE { delete $_[0]->{$_[1]} }

sub CLEAR {
printf "CLEAR\n";
%{$_[0]} = ()
}

sub SCALAR { scalar %{$_[0]} }
}


my %a = (a => Foo->new('a'), b => Foo->new('b'));

my %b;
tie(%b, "FooHash");
%b = %a;

my @a;

print "=== sort a\n";
@a = sort(values(%a));
printf "--> %s\n", join(' ', map { $_->val() } @a);

print "=== sort b\n";
@a = sort(values(%b));
printf "--> %s\n", join(' ', map { $_->val() } @a);

print "=== sort values b indirectly\n";
@a = values(%b);
@a = sort(@a);
printf "--> %s\n", join(' ', map { $_->val() } @a);
 
 
 

Class instances with 'use overload' in a tied hash

Post by Guy Bolton » Wed, 30 Mar 2005 01:39:36


Yes, I've posted code that doesn't work. Working code attached.

---snip!---

#!/usr/bin/env perl

use strict;
use warnings FATAL => 'all';

{
package Foo;

sub new {
my $self = bless({}, shift());
$self->{val} = shift();
return $self;
}

sub compare {
my ($self, $other) = @_;
return $self->{val} cmp $other->{val};
}

sub val {
return $_[0]->{val};
}

use overload
'cmp' => sub {
print "operator cmp\n";
return compare(@_);
},
'""' => sub {
printf "operator \"\" -> %s (%s)\n",
$_[0]->{val}, join(' ', caller());
return val(@_);
};
}


{
package FooHash;

sub TIEHASH { bless {}, $_[0] }

sub STORE {
printf "STORE(%s)\n", $_[1];
$_[0]->{$_[1]} = $_[2];
}

sub FETCH {
printf "FETCH(%s)\n", $_[1];
return $_[0]->{$_[1]};
}

sub FIRSTKEY {
print "FIRSTKEY\n";
keys %{$_[0]};
return $_[0]->NEXTKEY();
}

sub NEXTKEY {
my @result = each %{$_[0]};
print "NEXTKEY\n";
return wantarray ? @result : scalar(@result) ? $result[0] : undef;
}

sub EXISTS {
printf "EXISTS(%s)\n";
exists $_[0]->{$_[1]};
}

sub DELETE { delete $_[0]->{$_[1]} }

sub CLEAR {
printf "CLEAR\n";
%{$_[0]} = ()
}

sub SCALAR { scalar %{$_[0]} }
}


my %a = (a => Foo->new('a'), b => Foo->new('b'));

my %b;
tie(%b, "FooHash");
%b = %a;

my @a;

print "=== sort a\n";
@a = sort(values(%a));
printf "--> %s\n", join(' ', map { $_->val() } @a);

print "=== sort b\n";
@a = sort(values(%b));
printf "--> %s\n", join(' ', map { $_->val() } @a);

print "=== sort values b indirectly\n";
@a = values(%b);
@a = sort(@a);
printf "--> %s\n", join(' ', map { $_->val() } @a);

 
 
 

Class instances with 'use overload' in a tied hash

Post by Brian McCa » Wed, 30 Mar 2005 02:22:22


Good illustration.

I was able to reproduce on 5.8.6.

I'm fairly sure you've found a bug in Perl.
 
 
 

Class instances with 'use overload' in a tied hash

Post by Ala Qumsie » Wed, 30 Mar 2005 08:12:01


I wonder if this is related to the nested sort bug:

http://www.yqcomputer.com/
(you can login as guest/guest).

--Ala
 
 
 

Class instances with 'use overload' in a tied hash

Post by Guy Bolton » Wed, 30 Mar 2005 17:19:11


Right, I hadn't thought to check perlbug. My bad. Could be related to
http://www.yqcomputer.com/ (which seems to have
been thoroughly ignored, although I must admit that the usage there is
somewhat *** ).

Will submit bug, thanks all,

Guy.
 
 
 

Class instances with 'use overload' in a tied hash

Post by anno400 » Fri, 01 Apr 2005 20:13:03

Brian McCauley < XXXX@XXXXX.COM > wrote in comp.lang.perl.misc:


Looks like it.

An alternative workaround is

sort( map $_, values(%b));

Usually, "map $_, ..." should be a no-op, but here it isn't.

Anno
 
 
 

Class instances with 'use overload' in a tied hash

Post by Guy Bolton » Sat, 02 Apr 2005 20:05:43


XXXX@XXXXX.COM (Anno Siegel) writes:



John Peacock's followup in http://www.yqcomputer.com/
shows some mysterious Devel::Peek output; I had a look at hv.c in
5.8.6, but it was unsurprisingly unenlightening...


Thanks for that; however, I've opted to excise all instances of 'use
overload' from my code as I _need_ tied hashes, but overload is a
convenience (after all, we live without it in Java), and I don't want
to have to care whether the hash I'm using is tied or not, and I
certainly don't want to write suspicious-looking no-ops like 'sort(map
$_, values(%b))' for all hashes!

Would I be right in thinking that 'use overload' has been seen to
behave mysteriously in other contexts? It's a pity; value types are
nice to have.

Guy.
 
 
 

Class instances with 'use overload' in a tied hash

Post by anno400 » Sat, 02 Apr 2005 20:25:57

Guy Bolton King < XXXX@XXXXX.COM > wrote in comp.lang.perl.misc:

[use overload]


[...]


I use overload almost routinely for stringification (and then more often
than not either switch off autogeneration or overload "bool", but I
digress...).

Apart from the one discussed here, which was new to me, I know of
one more bug in overload. I forget the specifics, but it has to do
with changing overload behavior at run time, which doesn't seem to
catch on until something is blessed into the overloading package.
That happens rarely enough to live with. YMMV.

Anno