perlsubroutinelvalue

Can a reference to an lvalue subroutine be used as an lvalue?


I'm having trouble using a Perl subroutine reference as an lvalue. Am I doing something wrong here, or is it not possible to do this? I'm using ActiveState Perl 5.20 on Windows.

package Warning {
  use strict;
  use warnings;
  use Carp 'carp';
  sub new { 
    my $class = shift;
    return bless [@_], $class;
  }
  sub initbyname {
    my $self = shift;
    $self = $self->new unless ref $self;
    carp "'Warning' object already initialized" if @$self;
    while (@_) {
      my $method = shift;
      my $value = shift;
      my $sub = $self->can($method);
      $sub ? ( $sub->() = $value ) : 
          ( carp "method '$method' not found" );
     }
     return $self;
  }
  sub biff :lvalue { $_[0]->[ 0] }
  sub boff :lvalue { $_[0]->[ 1] }
}

package ThisWorks {
  use strict;
  use warnings;
  use Carp 'carp';
  sub new { 
    my $class = shift;
    return bless [@_], $class;
  }
  sub initbyname {
    my $self = shift;
    $self = $self->new unless ref $self;
    carp "'ThisWorks' object already initialized" if @$self;
    while (@_) {
      my $method = shift;
      my $value = shift;
      $self->can($method) ? ( $self->$method = $value ) :
          ( carp "method '$method' not found" );
     }
     return $self;
  }
  sub riff :lvalue { $_[0]->[ 0] }
  sub roff :lvalue { $_[0]->[ 1] }
}

package main;
use v5.20;
use strict;
use warnings;
my $warning   = Warning->initbyname( boff => 12 );
my $thisworks = ThisWorks->initbyname( roff => 13 );
say "warning->boff = ", $warning->boff // "uninitialized!";
say "thisworks->roff = ", $thisworks->roff;

Prints:

Useless assignment to a temporary at a.pl line 17.
warning->boff = uninitialized!
thisworks->roff = 13

Solution

  • The issue is that boff assigns to $_[0]->[1], but you are calling boff without any argument.

    $sub->()
    

    is supposed to be

    $sub->( $self )