19

I don't understand what could be the uses of lvalue subroutines? What is it that I can't accomplish with normal subroutines? Could you please post some examples?

Thanks

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Geo
  • 93,257
  • 117
  • 344
  • 520

4 Answers4

21

You can use lvalue subs as setters for object members:

sub x : lvalue {
    my $self = shift;
    $self->{x};
}

Then later:

$foo->x = 5;

This combines the intuitiveness of setting members directly with the flexibility of encapsulating the setter, in case you later want to change how the object is implemented. Compare to the following more traditional ways to set members in Perl:

Intuitive but fragile; what if you change how $foo is implemented?

$foo->{x} = 5;

Traditional setter method; doesn't use assignment syntax for what amounts to an assignment:

$foo->set_x(5);

Of course, lvalue methods have never really been embraced by the Perl community, and use of lvalue subs is "weird" and whatever would be gained for intuitiveness would be lost by the strangeness of it all.

nohat
  • 7,113
  • 10
  • 40
  • 43
  • 2
    Note that just like the [manual](https://perldoc.perl.org/perlsub.html#Lvalue-subroutines) states, using lvalue subs for setters like this precludes the possibility of validating input. In other words, using lvalue subs as accessors is strictly less powerful than a plain method. – yati sagade Dec 28 '17 at 15:29
  • Yeah, just like 'struct' members in 'C' or C++ -- nothing validates assignment to a struct member. Yet no one cites that as a problem with 'struct's. – Astara Apr 25 '18 at 22:47
15

LValues are recommended to be avoided. They're fun and all, but they confuse new users who make assumptions about how all subs work, and thus it should be avoided in code when a better way is available.

Sometimes it can be extremely practical to use an LValue result to do dirty work.

substr( $string, $start, $stop ) = 'somevalue' # replaces the specified part of the substring. 

However, this also does the same thing:

substr( $string, $start, $stop , 'somevalue' ); 

The difference here being mostly the former has significantly more expressive power, as it delegates the behaviour to the code that uses it instead of the function itself.

For instance:

substr( $string, $start, $stop ) =~ s/a/b/g 

Would require you to do

my $x = substr( $string, $start, $stop ); 
$x =~ s/a/b/g/; 
substr( $string, $start, $stop, $x );

Which is a bit nasty.

Although, there's an additional nasty here, because you have to think about whether doing that substitution or not with $x works retroactively to modify the string or not ( due to substr being an LValue sub). I don't think it does, but Its ambiguous enough I have to check the manual to remember whether it does or not, and that's bad.

temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
Kent Fredric
  • 56,416
  • 14
  • 107
  • 150
  • 2
    $x contains a copy, not an lvalue. But if you alias an lvalue substr ala `for (substr(...)) {` or `foo(substr(...))` you can do more than one thing with the lvalue. – ysth Aug 09 '10 at 21:11
  • I'm having trouble understanding some of your phrases: A) "to use an LValue result to do dirty work." but I can't see that ilustrated in the example--or I don't understand what you mean by "an LValue result" B) "as it delegates the behaviour to the code that uses it instead of the function itself." maybe it's about being non-native English, but I'm confused about meanings of pronouns here – Alois Mahdal Mar 15 '13 at 22:06
  • and C) "because you have to think about whether doing that substitution or not with $x works retroactively to modify the string or not"--too unclear to me, can't even point out how exactly... – Alois Mahdal Mar 15 '13 at 22:15
9

They provide a different interface, that in some circumstances can be more intuitive. Unlike traditional setters, you can actually change the value directly. For example

lvalue_sub($foo) =~ s/foo/bar/;

can be cleaner than

my $tmp = some_sub($foo);
$tmp =~ s/foo/bar/;
some_sub($foo, $tmp);
Leon Timmermans
  • 30,029
  • 2
  • 61
  • 110
6

I can't speak for using them much in my normal Perl stuff, but they are used extensively in the Perl Data Language when taking slices or other subsections of a piddle. For example:

my $a = sequence(100);
# use lvalue in this increment:
$a->where($a < 10)++;

# Zero-out the last four elements
# notice the use of the overloaded .= operator:
$a->slice("-10:") .= 0;

Like many things in Perl, this feature is not used much across the whole ecosystem, but its use at least in this niche makes life much easier for users of PDL.

David Mertens
  • 61
  • 1
  • 1