Overloaded stringification lost

E

Eric

It seems that if you define a custom stringification subroutine within
a package that has an AUTOLOAD subroutine, the stringification
subroutine is 'forgotten' after it has been called once (my
speculation). You can bless the object again to get the
stringification to work one more time...

The following code demonstrates the effect. Sorry for the length, I
did tried to simplify it as much as possible. I am running Perl 5.8.

use strict;
use warnings;

my $model = Model->new({type => { id => 'Foo' }});
print "1: ", $model->type, "\n"; # prints Foo
print "2: ", $model->type, "\n"; # prints Model=HASH(0x804c844)
my $type = $model->type;
bless $type, 'Model';
print "3: ", $type, "\n"; # prints Foo

package Model;

use overload '""' => \&_string;

sub new
{
my ($class, $data) = @_;
return bless $data,
ref($class) || $class;
}

sub _string
{
my ($self) = @_;
return $self->id || '?';
}

sub AUTOLOAD
{
(my $field = our $AUTOLOAD) =~ s/.*:://;
no strict 'refs';
*$field = sub { my ($self) = @_; return $self->_get($field) };
goto &$field;
}

sub _get
{
my ($self, $key) = @_;
return $self->_get_scalar($self->{$key})
if exists $self->{$key};
}

sub _get_scalar
{
my ($self, $value) = @_;
$value = $self->new($value)
if (ref $value eq 'HASH');
return $value;
}
 
A

Anno Siegel

Eric said:
It seems that if you define a custom stringification subroutine within
a package that has an AUTOLOAD subroutine, the stringification

No, AUTOLOAD isn't the culprit.
subroutine is 'forgotten' after it has been called once (my
speculation). You can bless the object again to get the
stringification to work one more time...

The following code demonstrates the effect. Sorry for the length, I
did tried to simplify it as much as possible. I am running Perl 5.8.

Your Model class is, frankly, a mess. The accessors (autoloaded or
not), try to pull a hashref out of the object and *bless* that into
the same class the object is from. That is, to put it mildly, an
unusual action for an accessor. The purpose of an accessor is to
get at the components of an object, not to present you with new
objects of the same type.

Also, your implementation of ->new must be the most generic one
I have ever seen. It simply blesses any scalar you give it into
any class you give it. A little sanity checking would be in order.

For the problem at hand, I haven't fully analyzed what's happening,
but the problem is not AUTOLOAD.

In the test code, OVERLOAD is activated twice, once to create the
accessor ->type, and another time (already in overload) to create
the accessor ->id. To see that AUTOLOAD is not the source of your
problem, pre-define the two accessors the way AUTOLOAD would:

sub type { $_[ 0]->_get( 'type') }
sub id { $_[ 0]->_get( 'id') }

After that, your test code doesn't call AUTOLOAD (rename it to
AUTOLOAD_off to be sure), but the behavior is the same.

My advice: Check the design of class Model, in particular the
action of your proposed accessors. If you're sure they do what
you want them to do, implement and debug the class *without*
AUTOLOAD. You'll need some scaffolding for that to pre-define
the accessors AUTOLOAD would otherwise create. Introduce
AUTOLOAD only after you're sure everything works as intended.

Anno

[code for reference]
 
E

Eric

No, AUTOLOAD isn't the culprit.

You're right.

After adding the following code to the _get_scalar method (before
returning the $value) everything works fine:

bless $value, 'Model'
if ref $value eq 'Model';

Weird...
 
A

Anno Siegel

Eric said:
You're right.

After adding the following code to the _get_scalar method (before
returning the $value) everything works fine:

bless $value, 'Model'
if ref $value eq 'Model';

Weird...

Well, frankly, your class is pretty weird to begin with :)

Anyway, you *may* have hit upon a known bug, not in overload, but
one that shows up in overload under certain conditions. It's been
a while and I'm hazy on the details, but the workaround was to bless
something into the overloading class to make overloading work as
expected. That could be the reason why the no-op appears to have
an effect. Maybe Ilya can add a word to this.

Anno
 

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,769
Messages
2,569,582
Members
45,058
Latest member
QQXCharlot

Latest Threads

Top