[Melbourne-pm] When is an lvalue an lvalue?

Jacinta Richardson jarich at perltraining.com.au
Mon Feb 20 18:17:23 PST 2012

On 20/02/12 18:24, Tim Connors wrote:
> And yet the following exits:
>          $md5->add(substr($$dataRef, $seekPosn, 131072));
> (part of lib/BackupPC/Lib.pm in backuppc, triggered by BackupPC_tarPCCopy
>   -  I'm pretty sure it's raising an exception, but the path is tortuous,
> not least because I wasn't quite sure why the exit code was 0, but then I
> just realised I was then piping the output to tar on another machine.
> duh)
> My workaround stops the premature bailing out:
>          my $tmp_str = substr($$dataRef, $seekPosn, 131072);
> #print STDERR "gothere3\n";
>          $md5->add($tmp_str);

Ooo, that's really interesting.

I originally thought the issue was that you were passing in a literal (the 
return value of substr) and then attempting to change it, despite your 
conviction that it isn't being changed.  But it looks likes the return value of 
substr *isn't* a literal, it's a magical anchor (which makes sense given the 
lvalue stuff).  This means it's not a copy of your data, it *is* your data.  
That's fascinating.

And awesome.  I've always thought you had to do the lvalue stuff like this:

     substr($string, $offset, $length) = $replacement;

But instead, if it's an anchor, then it means you can do this:

     use v5.10.0;
     my $string = "The quick brown fox jumps over the lazy dog";
     my $offset = 16;
     my $length = 3;
     my $replacement = "kitten";

     say $string;
     naughty( substr($string, $offset, $length) );
     say $string;

     sub naughty {
         $_[0] = $replacement;

     The quick brown fox jumps over the lazy dog
     The quick brown kitten jumps over the lazy dog

But of course if you instead call:

      naughty( substr($string, 100, 1) );

then you get:

     substr outside of string at substr.pl line ...

But if you can capture those anchors... that's awesome.  So then you can do 
stuff like this:

     naughty2( $string, substr($string, 16, 3), substr($string, 40, 3));
     say $string;

     sub naughty2 {
         # mess with $string if you want...
         substr($_[0], 3, 16, "elephant");

         # mess with the anchors
         $_[1] = "eel";
         $_[2] = "running horse";

     # and then wonder what comes out
     The quick brown eelphant jumps over the running horsey dog

> Not really an lvalue, is it?  I can sort of see why it does that - it
> doesn't know that the value is being passed to a function that isn't then
> going to modify its arguments, but ... counterintuitive.  I wonder if
> there's another way substr could have handled the returning of null data
> that pleases legacy programs that don't follow perl best practices.

So, while I can't actually answer your question, I can agree entirely that 
you're dealing with lvalue magic.  :)

This is indeed an issue only with 3 argument substr.  Although, interestingly, 
it seems that the 4 argument substr still returns an anchor into the string, 
just not a magical string changing one.  Otherwise:

     naughty2( $string, substr($string, 16, 3, "hippopotamus"), substr($string, 
40, 3));

would throw an error (about modifying a literal), and it doesn't.


More information about the Melbourne-pm mailing list