Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > "Can't return a temporary from lvalue subroutine..."

Reply
Thread Tools

"Can't return a temporary from lvalue subroutine..."

 
 
J Krugman
Guest
Posts: n/a
 
      07-18-2005




I'm OK with coding objects, but I find tied variables a bit
terrifying...

Anyway, it is common to implement objects as hashes (or rather as
references to hashes). My question is, is it possible to use a
(reference to a) tied hash instead of a (reference to a) regular
hash for this? I would have thought yes, but if I try to use a
tied hash instead of a regular hash I get this strange error

Can't return a temporary from lvalue subroutine...

This happens when I attempt to assign to an lvalue method (which
works fine if I don't use the tied hash).

What "temporary" is the error message referring to? Is there a
work around?

I give the relevant code below.

TIA,

jill

package Helper;
use Tie::Hash;
our @ISA = 'Tie::StdHash';

sub STORE {
my ($self, $key, $value) = @_;
warn "storing value $value under key $key\n";
$self->{$key} = $value;
}

1;
__END__

package My_Class;
use Helper;

sub new {
my $class = shift;
my %self = ();
tie %self, 'Helper'; # OK if this line is commented out
return bless \%self, $class;
}

sub var : lvalue {
my $self = shift;
$self->{_var_} = shift if @_;
$self->{_var_};
}

1;
__END__

use My_Class;

my $v = My_Class->new();
$v->var = 42; # fatal error


--
To s&e^n]d me m~a}i]l r%e*m?o\v[e bit from my a|d)d:r{e:s]s.

 
Reply With Quote
 
 
 
 
Mr P
Guest
Posts: n/a
 
      07-18-2005


J Krugman wrote:
> I'm OK with coding objects, but I find tied variables a bit
> terrifying...
>
>


 
Reply With Quote
 
 
 
 
Anno Siegel
Guest
Posts: n/a
 
      07-18-2005
J Krugman <> wrote in comp.lang.perl.misc:
>
>
>
>
> I'm OK with coding objects, but I find tied variables a bit
> terrifying...


It's quite ordinary magic.

> Anyway, it is common to implement objects as hashes (or rather as
> references to hashes). My question is, is it possible to use a
> (reference to a) tied hash instead of a (reference to a) regular
> hash for this? I would have thought yes, but if I try to use a
> tied hash instead of a regular hash I get this strange error
>
> Can't return a temporary from lvalue subroutine...
>
> This happens when I attempt to assign to an lvalue method (which
> works fine if I don't use the tied hash).
>
> What "temporary" is the error message referring to? Is there a
> work around?


It looks like "temporary" refers to the state of a scalar of being
"mortal". Mortal SVs are all over the Perl source, but normally
only concern XS programmers. This is the first time I see the
distinction appear at Perl level.

> I give the relevant code below.


The code is reasonable, I would have written it similarly, except for

> sub var : lvalue {
> my $self = shift;
> $self->{_var_} = shift if @_;


This line is now redundant, or it would be if the code worked as expected.
You're assigning through the lvalue now. It isn't exactly wrong to have
it, but it distracts from the purpose of the lvalue-method.

> $self->{_var_};
> }


I, too would have expected the construction to work. I'm not sure what's
wrong, but then lvalue subs are still (permanently?) experimental, so
irregularities must be expected.

For a workaround, instead of tying the whole hash, you can tie each
hash value to a scalar. That works without the error. Like a good
workaround, it has serious disadvantages.

For one, you must either pre-tie all fields in the ->new method of
My_Class, in which case you can't add fields dynamically. If you must
do that, the ->var method(s) must do the tying on the fly when a new
key is generated.

Another problem is that the STORE method of a tied scalar doesn't know
about the hash key the value is stored under. Since each tied scalar
belongs to a fixed key, it would be possible to store the hash key in
the tying object (the one in Tie::Scalar...). But that's extra work,
and it means you can't use Tie::StdScalar as is, because it has no
provisions for extra values.

I suppose your motivation is that you like the idea of lvalue methods,
but need more control over what gets stored by careless users in your
sensitive objects. A similar problem exists with objects that expose
(parts of) their interior though overloading a dereference operator,
say %{}. Like lvalues, it gives you pretty syntax, but leaves your
objects wide open. I have used tied hashes to correct this (that is,
returned a reference to a tied hash in response to %{ $obj}, and haven't
encountered the particular difficulty you're seeing. That may be
an alternative approach.

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      07-18-2005
Mr P <> wrote in comp.lang.perl.misc:
> J Krugman wrote:
> > I'm OK with coding objects, but I find tied variables a bit
> > terrifying...
> >
> >

>
> .
> .
> .
>
> terrifying?? Dude if a programming language is terrifying do NOT watch
> the news tonight! Indimidating I think is what you meant?


[...]

> Tying is a way to tell the O/S "store THIS variable result on disk, NOT
> in memory". That's pretty much it as long as your variable construct is
> simple. If not, its more more involved since "tying" only supports
> simple structures. To get beyond that you may need data dumper or
> something else.


You speak with authority, MisterPerl, but you are wrong. Tying as such
has nothing to do with storage on disk, or complexity of data structures.

What you say is more or less true of tying to one of the *DBM_File
modules, but you seem to be unaware of other applications of tie().

Jill's question is about one of those other applications.

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
 
Reply With Quote
 
J Krugman
Guest
Posts: n/a
 
      07-19-2005
In <dbgjls$l1e$> (Anno Siegel) writes:

>J Krugman <> wrote in comp.lang.perl.misc:


>> I give the relevant code below.


>The code is reasonable, I would have written it similarly, except for


>> sub var : lvalue {
>> my $self = shift;
>> $self->{_var_} = shift if @_;


>This line is now redundant, or it would be if the code worked as expected.
>You're assigning through the lvalue now. It isn't exactly wrong to have
>it, but it distracts from the purpose of the lvalue-method.


My thought was to give users the option setting through the lvalue
*or* through the more conventional

$self->var(1);

....but maybe this is not such a hot idea...

>For a workaround, instead of tying the whole hash, you can tie each
>hash value to a scalar.


That's good to know. I was under the mistaken impression that only
"simple" scalar variables (i.e. like $foo, as opposed to $foo{bar})
could be tied to scalars.

>For one, you must either pre-tie all fields in the ->new method of
>My_Class, in which case you can't add fields dynamically. If you must
>do that, the ->var method(s) must do the tying on the fly when a new
>key is generated.


You lost me there, Anno. I don't see how, in general, an lvalue
method could do any on-the-fly tying, since all but the last
statement of the method are ignored when it is used as an lvalue.
(Yes, it could do it if it is being used as a non-lvalue method,
but that imposes a strange API).

>Another problem is that the STORE method of a tied scalar doesn't know
>about the hash key the value is stored under. Since each tied scalar
>belongs to a fixed key, it would be possible to store the hash key in
>the tying object (the one in Tie::Scalar...). But that's extra work,
>and it means you can't use Tie::StdScalar as is, because it has no
>provisions for extra values.


(A bit over my head, but that's OK: I know have a lot to learn.)

>I suppose your motivation is that you like the idea of lvalue methods,
>but need more control over what gets stored by careless users in your
>sensitive objects.


Exactly! Very clairvoyant of you.

>A similar problem exists with objects that expose
>(parts of) their interior though overloading a dereference operator,
>say %{}. Like lvalues, it gives you pretty syntax, but leaves your
>objects wide open. I have used tied hashes to correct this (that is,
>returned a reference to a tied hash in response to %{ $obj}, and haven't
>encountered the particular difficulty you're seeing. That may be
>an alternative approach.


I'm having a hard time picturing what you describe here. It seems
to imply that $obj somehow knows when it's being dereferenced (and
responds accordingly by "returning" a tied hash???), which I find
hard to understand. Is this something you do in any published code
that I could study?

Thank you very much for your post.

jill

--
To s&e^n]d me m~a}i]l r%e*m?o\v[e bit from my a|d)d:r{e:s]s.

 
Reply With Quote
 
attn.steven.kuo@gmail.com
Guest
Posts: n/a
 
      07-19-2005
Anno Siegel wrote:
> J Krugman <> wrote in comp.lang.perl.misc:
> >


(snipped)

> >
> > What "temporary" is the error message referring to? Is there a
> > work around?

>
> It looks like "temporary" refers to the state of a scalar of being
> "mortal". Mortal SVs are all over the Perl source, but normally
> only concern XS programmers. This is the first time I see the
> distinction appear at Perl level.



Found in the perl source code:

http://search.cpan.org/src/NWCLARK/perl-5.8.7/pp_hot.c

It appears values on the Perl stack are being checked for
their SvFLAGS to determine whether the subroutine is returning
a "temporary".


(snipped)

>
> For a workaround, instead of tying the whole hash, you can tie each
> hash value to a scalar. That works without the error. Like a good
> workaround, it has serious disadvantages.
>
> For one, you must either pre-tie all fields in the ->new method of
> My_Class, in which case you can't add fields dynamically. If you must
> do that, the ->var method(s) must do the tying on the fly when a new
> key is generated.
>
> Another problem is that the STORE method of a tied scalar doesn't know
> about the hash key the value is stored under. Since each tied scalar
> belongs to a fixed key, it would be possible to store the hash key in
> the tying object (the one in Tie::Scalar...). But that's extra work,
> and it means you can't use Tie::StdScalar as is, because it has no
> provisions for extra values.



It seems the Class::Accessor::Lvalue module on CPAN uses
this approach to implement lvalue methods.

--
Regards,
Steven

 
Reply With Quote
 
Tassilo v. Parseval
Guest
Posts: n/a
 
      07-19-2005
Also sprach J Krugman:

> In <dbgjls$l1e$> (Anno Siegel) writes:
>
>>J Krugman <> wrote in comp.lang.perl.misc:


>>For a workaround, instead of tying the whole hash, you can tie each
>>hash value to a scalar.

>
> That's good to know. I was under the mistaken impression that only
> "simple" scalar variables (i.e. like $foo, as opposed to $foo{bar})
> could be tied to scalars.


Not at all. If that was the case, you couldn't store a tied scalar in
an array or hash thusly:

tie my $scalar => 'Class';
$hash{ key } = $scalar;

>>For one, you must either pre-tie all fields in the ->new method of
>>My_Class, in which case you can't add fields dynamically. If you must
>>do that, the ->var method(s) must do the tying on the fly when a new
>>key is generated.

>
> You lost me there, Anno. I don't see how, in general, an lvalue
> method could do any on-the-fly tying, since all but the last
> statement of the method are ignored when it is used as an lvalue.
> (Yes, it could do it if it is being used as a non-lvalue method,
> but that imposes a strange API).


It can be done quite easily:

sub var : lvalue {
my $self = shift;
tie $self->{_var_} => 'Class';
$self->{_var_};
}

Also, it's not at all true that only the last statement in a
lvalue-function is executed. It's just so that the last statement has to
be the (non-temporary) scalar you want to assign to.

>>Another problem is that the STORE method of a tied scalar doesn't know
>>about the hash key the value is stored under. Since each tied scalar
>>belongs to a fixed key, it would be possible to store the hash key in
>>the tying object (the one in Tie::Scalar...). But that's extra work,
>>and it means you can't use Tie::StdScalar as is, because it has no
>>provisions for extra values.

>
> (A bit over my head, but that's OK: I know have a lot to learn.)


I've read this paragraph a few times now. I am not quite sure either
what Anno is referring to.

>>A similar problem exists with objects that expose
>>(parts of) their interior though overloading a dereference operator,
>>say %{}. Like lvalues, it gives you pretty syntax, but leaves your
>>objects wide open. I have used tied hashes to correct this (that is,
>>returned a reference to a tied hash in response to %{ $obj}, and haven't
>>encountered the particular difficulty you're seeing. That may be
>>an alternative approach.

>
> I'm having a hard time picturing what you describe here. It seems
> to imply that $obj somehow knows when it's being dereferenced (and
> responds accordingly by "returning" a tied hash???), which I find
> hard to understand. Is this something you do in any published code
> that I could study?


You can overload the hash-dereference operator for a class:

package Class;

use overload '%{}' => sub {
my $self = shift;
$self->[0];
};

sub new {
my ($class) = @_;
bless [
{
key1 => 'value1',
key2 => 'value2',
},
] => $class;
}

package main;

use Data:umper;
my $obj = Class->new;
print Dumper $obj;
%$obj = (key3 => 'value3');
print Dumper $obj;

__END__
$VAR1 = bless( [
{
'key2' => 'value2',
'key1' => 'value1'
}
], 'Class' );
$VAR1 = bless( [
{
'key3' => 'value3'
}
], 'Class' );

By returning a reference to a tied-hash in the overload-handler of '%{}'
one could then control what is stored in $self->[0].

Tassilo
--
use bigint;
$n=71423350343770280161397026330337371139054411854 220053437565440;
$m=-8,;;$_=$n&(0xff)<<$m,,$_>>=$m,,print+chr,,while(($ m+=<=200);
 
Reply With Quote
 
Tassilo v. Parseval
Guest
Posts: n/a
 
      07-19-2005
Also sprach :

> Anno Siegel wrote:
>> J Krugman <> wrote in comp.lang.perl.misc:
>> >

>
> (snipped)
>
>> >
>> > What "temporary" is the error message referring to? Is there a
>> > work around?

>>
>> It looks like "temporary" refers to the state of a scalar of being
>> "mortal". Mortal SVs are all over the Perl source, but normally
>> only concern XS programmers. This is the first time I see the
>> distinction appear at Perl level.

>
>
> Found in the perl source code:
>
> http://search.cpan.org/src/NWCLARK/perl-5.8.7/pp_hot.c
>
> It appears values on the Perl stack are being checked for
> their SvFLAGS to determine whether the subroutine is returning
> a "temporary".


The temporary here is a red-herring, I think. Some time ago I was making
a patch that would allow perl to assign plain GLOBs to tied scalars
which was eventually applied. I remember I had a hard time understanding
the mechanisms behind tying and so I put them down for later reference
at <http://use.perl.org/~ethan/journal/16385>.

The problem with tying and lvalue functions is that both require to
return a special kind of Perl scalar, namely an SvPVLV. This happens to
be a temporary because it is no longer needed after the actual
assignment happens.

However, if you try to assign to a tied-scalar via an lvalue-function,
you're in big trouble because now you have two PVLV-scalars that somehow
have to be crammed into one.

I could be wrong here, though, because perl might be smart enough to
notice that only one of these two lvalue-scalars is needed (namely the
one belonging to the tied scalar). In this case the check of temporarity
you mentioned above could be extended to also check for tiedness of the
variable in which case a temporary might be ok.

There'd only need to be some provisions that this temporary is not
destroyed too early (that is: not before the deferred assignment
happens).

Tassilo
--
use bigint;
$n=71423350343770280161397026330337371139054411854 220053437565440;
$m=-8,;;$_=$n&(0xff)<<$m,,$_>>=$m,,print+chr,,while(($ m+=<=200);
 
Reply With Quote
 
Joe Smith
Guest
Posts: n/a
 
      07-19-2005
Mr P wrote:
> I often had trouble getting back the same data I put into the
> variable. I was told by users here things like
>
> "Oh don't use "SBMD_File, it's broken!"
>
> So I guess that's the most intimidating part- the apparent fact that
> some techniques are "broken". Read on here to find the "unbroken" ones.
> If you're using a small dataset, they all will probably work. As you
> get into larger ones, that may no longer be true. Beware. Choose one
> that seems to work for most datasets. "NDBM_File" or "GDBM_File" are
> probably OK choices.


No, NDBM_File is not OK. To quote from 'perldoc AnyDBM_File':

Here's a partial table of features the different packages offer:

odbm ndbm sdbm gdbm bsd-db
---- ---- ---- ---- ------
Linkage comes w/ perl yes yes yes yes yes
Src comes w/ perl no no yes no no
Comes w/ many unix os yes yes no no no
Builds ok on !unix ? ? yes yes ?
Code Size ? ? small big big
Database Size ? ? small big? ok
Speed ? ? slow ok fast
FTPable no no yes yes yes
Easy to build N/A N/A yes yes ok
Size limits 1k 4k 1k none none
Byte-order independent no no no no yes
Licensing restrictions ? ? no yes no

I got burned by the 4K limit in ndbm. What I understand is that all
keys that hash to the same value are stored in the same hash bucket.
If one bucket fills up before it is time to split the buckets, you're
screwed. The number of entries you can put into an ndbm hash before
it crashes is nondeterministic: it is significantly affected by the
order in which items are added. It's OK to use ndbm for a few thousand
entries with short keys (like "username" or "192.168.1.2"), but not
for the big stuff.
-Joe
 
Reply With Quote
 
Brian McCauley
Guest
Posts: n/a
 
      07-19-2005


Anno Siegel wrote:
> J Krugman <> wrote in comp.lang.perl.misc:
>
>>sub var : lvalue {
>> my $self = shift;
>> $self->{_var_};
>>}

>
> I, too would have expected the construction to work. I'm not sure what's
> wrong, but then lvalue subs are still (permanently?) experimental, so
> irregularities must be expected.
>
> For a workaround, instead of tying the whole hash, you can tie each
> hash value to a scalar. That works without the error. Like a good
> workaround, it has serious disadvantages.


Another work-round is not to have any persitant ties and to have the
accessor create a tied scalar on the fly. This approach can put the
validation inside the accessor method which I think aids redability.

use Tie::OneOff;

sub var : lvalue {
my $self = shift;
Tie::OneOff->lvalue({
FETCH => sub { $self->{_var_} },
STORE => sub {
my $newval = shift;
# validate $newval
$self->{_var_} = $newval;
},
});
}



>
> For one, you must either pre-tie all fields in the ->new method of
> My_Class, in which case you can't add fields dynamically. If you must
> do that, the ->var method(s) must do the tying on the fly when a new
> key is generated.
>
> Another problem is that the STORE method of a tied scalar doesn't know
> about the hash key the value is stored under. Since each tied scalar
> belongs to a fixed key, it would be possible to store the hash key in
> the tying object (the one in Tie::Scalar...). But that's extra work,
> and it means you can't use Tie::StdScalar as is, because it has no
> provisions for extra values.
>
> I suppose your motivation is that you like the idea of lvalue methods,
> but need more control over what gets stored by careless users in your
> sensitive objects. A similar problem exists with objects that expose
> (parts of) their interior though overloading a dereference operator,
> say %{}. Like lvalues, it gives you pretty syntax, but leaves your
> objects wide open. I have used tied hashes to correct this (that is,
> returned a reference to a tied hash in response to %{ $obj}, and haven't
> encountered the particular difficulty you're seeing. That may be
> an alternative approach.
>
> Anno


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
using a method as an lvalue and "invalid lvalue in assignment"compilation error markryde@gmail.com C Programming 11 09-22-2008 10:42 AM
lvalue and assignment to temporary object subramanian100in@yahoo.com, India C++ 3 12-21-2007 01:32 PM
Temporary as lvalue Vyacheslav Kononenko C++ 2 12-15-2006 06:06 AM
operators requiring lvalue/rvalue operands and resulting in rvalue/lvalue Kavya C Programming 9 10-28-2006 01:45 AM
Perl hangs when returning lvalue closure from another lvalue closure Julian Mehnle Perl Misc 0 07-17-2003 03:13 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57