Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

lvaluable AUTOLOAD (help! Abigail! someone!)

0 views
Skip to first unread message

Dodger

unread,
May 6, 2008, 6:53:36 AM5/6/08
to
I decided I wanted to see if I could reproduce the effects of some
pretty common code in Perl. For instance, the Ruby version:

class Book
attr_reader :title
attr_accessor :price

def initialize(title, price)
@title, @price = title, price
end
end

or more verbosely in Ruby:

class Book
def initialize(title, price)
@title, @price = title, price
end

def title
@title
end

def price
@price
end

def price=(price)
@price = price
end
end

This is basically a case of price being a public property and title
being a protected one (i.e. only a read, no accessor).

So it seemed that with all the things Perl can do I should have been
able to do the same thing in Perl, right? Maybe with a little
finagling, but it hsould be possible.

I came up with this code:

package Book;
use strict;
our $AUTOLOAD;

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

$self->{_vars}->{protected} = [qw(title)];
$self->{_discard} = undef;

bless $self, ref $class || $class;

$self->{title} = shift;
$self->{price} = shift;

return $self;
}

sub AUTOLOAD : lvalue {
my $self = shift;
my $property = $AUTOLOAD;
$property =~ s/.*://;

if (exists $self->{$property}) {
if (grep $property eq $_, @{$self->{_vars}->{protected}}) {
warn "$property is Protected\n";
my $val = $self->{$property};
return $val;
}
$self->{$property};
}
else {
$self->{_discard};
}
}


Problem is, it doesn't work...

This code calling it dies at the second (price, the public one)
assignment attempt:

print "Title read: ", $book->title, "\n";
print "Price read: ", $book->price, "\n\n";

print "Title modify: ", $book->title = "Hello", "\n";
print "Price modify: ", $book->price = 5, "\n\n";

title is Protected
Title read: The Moon is a Harsh Mistress
Price read: 7.99

title is Protected
Title modify: Hello
Can't return a temporary from lvalue subroutine at lv.pl line 10.

Now, you aren't supposed to use return in an lvaluable subroutine, of
course... however, if I DON'T use a return, I get the error. And if I
do use return, the lvalue doesn't modify the actual thing.

Is there away around this? Can I make this work?

Granted, it's all for my own 'personal enrichment', not for any real
use or anything... still, I don't like the idea that I can't make
something work...

--
Sean 'Dodger' Cannon

Dodger

unread,
May 6, 2008, 7:13:07 AM5/6/08
to
On May 6, 3:53 am, I wrote:
> I decided I wanted to see if I could reproduce the effects of some
> pretty common code in Perl. For instance, the Ruby version:
> ...

> Is there away around this? Can I make this work?

BTW, I know of course I can easily do it without AUTOLOAD:

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

$self->{_vars}->{protected} = [qw(title)];
$self->{_discard} = undef;

bless $self, ref $class || $class;

$self->{title} = shift;
$self->{price} = shift;

return $self;
}

sub title {
shift->{title};
}

sub price : lvalue {
shift->{price};
}

That works fine. However, it seemed so strongly that I should be able
to do it with AUTOLOAD too...

--
Sean 'Dodger' Cannon

Darin McBride

unread,
May 6, 2008, 9:55:28 AM5/6/08
to
Dodger wrote:

> So it seemed that with all the things Perl can do I should have been
> able to do the same thing in Perl, right? Maybe with a little
> finagling, but it hsould be possible.

Take a look at Contextual::Return. It may provide enough syntactical sugar
to make this easy.

Rough guess, untested:

sub _any(&@) { my $s = shift; $s->() && return 1 for @_; return; }


sub AUTOLOAD :lvalue {
my $self = shift;

my ($property) = $AUTOLOAD) =~ /::([^:]+)$/;

if (_any { $property eq $_ }, @{$self->{_vars}{protected}}) {
return RVALUE { $self->{$property} }
LVALUE { require Carp; croak "Can't use $property as lvalue" }
}
$self->{$property}
}

Or something like that.

0 new messages