[% setvar title lvalue subs should receive the rvalue as an argument %]

This file is part of the Perl 6 Archive

Note: these documents may be out of date. Do not use as reference!

To see what is currently happening visit http://www.perl6.org/

TITLE

lvalue subs should receive the rvalue as an argument

VERSION

  Maintainer: Andy Wardley <abw@kfs.org>
  Date: 15 Aug 2000
  Mailing List: perl6-language@perl.org
  Number: 107
  Version: 1
  Status: Developing

ABSTRACT

This RFC proposes that lvalue subs, when invoked as such, should receive the rvalue being assigned to it as an argument.

DESCRIPTION

Take a simple object:

    package Person;
    sub new {
	my ($class, $name) = @_;
	bless { name => $name }, $class;
    }
    sub name {
	my $self = shift;
	if (@_) {
	    $self->{name} = shift;
	    print "changed name to $self->{name}\n";
	}
	return $self->{ name };
    }

We define a simple accessor method, name, to marshal access to the internal name field. In this example it prints a message when the name is changed but in the real world it might do something far more important. The method can be used to get or set this field.

    my $p = Person->new("Gandalf");
    print "name: $p->name\n";	    # "name: Gandalf"
    $p->name("Mithrandir");	    # "changed name to Mithrandir"
    print "name: $p->name\n";	    # "name: Mithrandir"

We can define this method as an lvalue sub allowing it to be used directly in assignment statements. Note that we must remove the 'return' in the last line of the method.

    sub name : lvalue {
	my $self = shift;
	if (@_) {		    # Danger Will Robinson!
	    $self->{name} = shift;
	    print "changed name to $self->{name}\n";
	}
	$self->{name};
    }

    package main;
    my $p = Person->new("Gandalf");
    $p->name = "Mithrandir";

This "works" in the sense that the Person name is updated, but it doesn't work the same as when called as a regular object method. The reason is that lvalue calls don't pass the new value to the method. Our check of @_ in the method returns false so the method doesn't know that an attempt is being made to update the field. Instead it blindy returns the internal field which Perl can then update directly, using some kind of hidden magic and trickery.

    $p->name('Gandalf');	    # "changed name to Gandalf"
    $p->name = 'Mithrandir';	    # !! silence !!
    print "name: $p->name\n";	    # "name: Mithrandir"

The Person name is now set to 'Mithrandir', but managed to bypass the marshalling code that we carefully constructed to trap any attempts to update this field. This is inconsistent and allows the object encapsulation to be violated.

It is proposed that lvalue subs should be called with the rvalue passed as a regular argument. Thus,

    $p->name = 'Mithrandir';

would be directly equivalent to

    $p->name('Mithrandir');

This would allow accessor methods to detect, and if necessary, intercept any attempts to update a particular field, even when called as an lvalue sub.

We might want to consider a general rule stating that the rvalue is added to the end of any existing argument list. This, it would be possible to do this:

    $obj->method($x, $y) = $z;

and have the method called as if written:

    $obj->method($x, $y, $z);

This might make more sense when combined with named parameters.

    $p->name(warnings => 0) = 'Mithrandir';
    $p->name(%options) = $value;

equivalent to:

    $p->name(warnings => 0, 'Mithrandir');
    $p->name(%options, $value);

This may be a bad thing. The author makes no judgement either way.

IMPLEMENTATION

Hopefully trivial.

REFERENCES

None