ysth has asked for the wisdom of the Perl Monks concerning the following question:

In notabug quiz, I didn't include this, because it actually does look like a bug to me. Can anyone explain why the returned values() are lvalues (but only for tied hashes) here:
#!/usr/bin/perl -w use strict; use warnings; use Tie::Hash; our %nottied = ('a'..'d'); tie our %tied, "Tie::StdHash"; %tied = ('a'..'d'); print "tied is: ", %tied, "\n"; print "nottied is: ", %nottied, "\n"; $_ = "x" for &{sub { values %tied }}; $_ = "x" for &{sub { values %nottied }}; print "tied is now: ", %tied, "\n"; print "nottied is now: ", %nottied, "\n"; __END__ output is: tied is: cdab nottied is: cdab tied is now: cxax nottied is now: cdab
  • Comment on not a notabug? sub returning values behaves differently for tied hash
  • Download Code

Replies are listed 'Best First'.
Re: not a notabug? sub returning values behaves differently for tied hash (aliases)
by tye (Sage) on Dec 14, 2003 at 22:41 UTC

    To pick a nit, I think the problem is that they are not aliases, not that they are not lvalues.

    From a Perl delta POD:

    perldelta - what's new for perl v5.6.0

    [...]

    =item delete(), values() and C<\(%h)> operate on aliases to values, not copies

    delete(), each(), values() and hashes in a list context return the actual values in the hash, instead of copies (as they used to in earlier versions). Typical idioms for using these constructs copy the returned values, but this can make a significant difference when creating references to the returned values. Keys in the hash are still returned as copies when iterating on a hash.

    See also L</"delete(), each(), values() and hash iteration are faster">.

    For example:
    require Tie::Hash; use vars qw( %h %t ); %h = ( a=>1 ); tie %t, 'Tie::StdHash'; %t = ( z=>9 ); eval { sub { values %h }->() += 10; }; warn "$@\n"; eval { sub { values %t }->() += 10; }; warn "$@\n"; print ref(\substr("hello",1,2)), $/; print ref(\sub { values %h }->()), $/; print $/; use vars qw( $a, $b, $c, $x, $y, $z ); print $a=\values %h, $/; print $b=\values %h, $/; print $c=\sub{values %h}->(), $/; print $/; print $x=\values %t, $/; print $y=\values %t, $/; print $z=\sub{values %t}->(), $/; print $/; $,= " "; $$x= 31; print $$x, $$y, values %t, $/; $$y= 32; print $$x, $$y, values %t, $/; $$x= 33; print $$x, $$y, values %t, $/; __END__ Can't modify non-lvalue subroutine call at values2.pl line 6. Can't modify non-lvalue subroutine call at values2.pl line 8. LVALUE SCALAR SCALAR(0x1a7f228) SCALAR(0x1a7f228) SCALAR(0x1aced54) SCALAR(0x1aced60) SCALAR(0x1aced78) SCALAR(0x1aced9c) 31 31 31 31 32 32 33 32 33
    I expected the last three references to all report the same address (showing that they are aliases) while the three above that wouldn't. In fact, this shows that the "aliasness" is not preserved in the tied case either but that Perl does some extra magic (that looks a lot like lvalueness but not quite) in order to make the results from values for tied hashes behave like aliases.

    Seeing this, I tested this magic some more with the last code, which looks like we have two separate scalars that each have magic telling them to update the tied hash if they are modified.

    But return @list isn't documented to return aliases to the values in @list so it is free to copy @list instead, so I don't think this is a bug. The enthusasism of the magic values returned by values on tied hashes is a bit surprising to me, but I'd need to dig a lot deeper before deciding if a change is warrented there.

                    - tye
Re: not a notabug? sub returning values behaves differently for tied hash
by pg (Canon) on Dec 14, 2003 at 22:36 UTC

    If I take away the complexity caused by returning from sub, then in both cases, 'x' got set:

    use strict; use warnings; use Tie::Hash; our %nottied = ('a'..'d'); tie our %tied, "Tie::StdHash"; %tied = ('a'..'d'); $_ = 'x' for (values %tied); $_ = 'x' for (values %nottied); print "tied is now: ", %tied, "\n"; print "nottied is now: ", %nottied, "\n";

    This gives you:

    tied is now: cxax nottied is now: cxax