[% setvar title Lvalue subroutines: implicit and explicit assignment %]
Note: these documents may be out of date. Do not use as reference! |
To see what is currently happening visit http://www.perl6.org/
Lvalue subroutines: implicit and explicit assignment
Maintainer: James Mastros <james@rtweb.net> Date: 24 Aug 2000 Mailing List: perl6-language-subs@perl.org Number: 149 Version: 1 Status: Developing
This RFC proposes two parallel methods for subroutines to be used as lvalues: implicit and explicit assignment. These methods are similar to the methods proposed previously in RFCs 107 and 118.
This is very similar to the lvalue subs in perl5.6, and to the method recommended in RFC 107.
It allows code such as
package Object; sub foo(\%inner) : method { return %inner{foo}; }
to be used as the lvalue in an assignment. It also allows it in a mutator context with single-evalutation, and allows it to be dynamically assigned to.
This requires, however, that the return statement not return the value of
%inner{foo}
, which is, after all, just a value and therefore cannot be
assigned to, but rather a reference thereto.
Therefore, the definition of the return function must be changed such that it is lazy.
Additionally, the definition of assignment must not normally evaluate a lazy
expression, but rather evaluate it to the point where its value would become
the value of a variable, and then assign to that variable. If the
expression cannot be evaluated to that point, (for example, $x+3
), then
it may be an error to assign to it.
(The may be is there because we might try solving the equation of the assignment until one side becomes the value of a variable, and then assigning the value to the variable such that it becomes true. This is almost certainly what is meant by the original expression. However, this almost certainly isn't worth the effort required.)
(This process could also be expressed in terms of automatic enreferencing and dereferencing, but this way seems more perlish.)
Given the definition of Object::foo
above, the code $obj->foo = 42;
should result in this process:
Object::foo($obj);
The arguments are processed in accordance with the parameter list of foo:
%inner = %$obj;
Object::foo
runs
Object::foo
returns.
$temp = lazy $inner{foo} # = $obj->{foo}
The assignment is preformed.
$temp = 42
The lazy expression is partially evaluated.
$temp => $obj->{foo}
The (real) assignment is preformed.
$obj->{foo} = 42;
The context of the LHS is propagated from the RHS. This implies that the RHS is evaluated first.
A lvalue sub using implicit assignment may be local()ized or safe()d using the normal methods.
In this form of lvalue sub, the sub is passed both it's LHS arguments and it's RHS value.
To indicate that the subrotuine may be called with explicit assignment, one or more of the elements of its parameter list must be declared with a :lvalue attribute.
The context of the RHS is determined by the declared calling convention of the lvalue sub. If and only if the lvalue sub is defined to take one scalar argument (not including a forced-reference [?]), then the RHS is evaluated in a scalar context. Otherwise, it is evaluated in a list context.
If more explicit contexts are added, then the context of the RHS exactly
matches that specified by the :lvalue
d elements of the LHS' parameter
list.
Given the code
sub mode(\%self; $mode :lvalue) { if ($mode <5 && $mode >= 0) { %self{mode} = $mode; } else { carp "Mode outside of range 0..5!"; } }
The code mode($foo) = 3;
executes by calling mode with %self = %$foo and
$mode = 3. The code mode($foo) = qw(3 4 5)
has the same effect, since
qw(3 4 5)
is it's lengh in scalar context. The code mode($foo)
executes by calling mode wih %self = %$foo and $mode undef (it would be an
error had the semicolon been a comma).
Note that the RHS is evaluated first, since it's context can be gathered from the signature of the lvalue sub.
Mutators are called with the lvalue part being the result of calling the function first in a rvalue context lazaly.
Thus, the code mode($foo)++
results in a call to mode($foo, lazy
mode($foo)+1);
. It is the lvalue sub's responsibility to make certain that
single-evaluation semantics are followed if it wishes to do so by decomposing
the lazy parameter. Such decomposition is outside the realm of this RFC.
It is not possible to local()
ize or safe()
ty an explicit-assignment style
lvalue sub in a manner transparent to that sub. For that reason, a closure
returning the current rvalue of the lvalue sub is created into a temporary.
The temporary is then evaluated and it's value assigned back to the call at
then end of the block (but only if the block exits cleanly in the case of a
safe() assignment).
Thus, given the definition of mode above,
{ local mode($foo) = 1; ...; }
Results in code equivalent to
{ my $temp = sub { mode($foo) }; #create a closure mode($foo) = 1; ...; mode($foo) = &$temp; #evaluate the closure }
Note that this results in three calls to the sub in response to one explicit assignment. This may be a very bad thing in some cases, but is unavoidable.
A subroutine may be marked as being in error to call in a lvalue context by
specifying a :nonlvalue
attribute on it. This prevents it from being
called as an implicit lvalue function.
RFC 118: lvalue subs: parameters, explicit assignment, and wantarray() changes: This is the basis for our explicit assignment section.
RFC 107: lvalue subs should receive the rvalue as an argument: This is the basis for our implicit assignment section.
RFC 132: subroutines should be able to return an lvalue:
We, in effect, always make the value returned by return
a valid
lvalue, so that the same code can be used for both the rvalue and
lvalue cases. This is in direct contradiction to the lreturn
keyword recommended here.
RFC 130: Transaction-enabled variables for Perl6: We discuss how lvalue subs can be safe()d in the Implementation sections.
RFC 128: Subroutines: Extend subroutine contexts to include named parameters and lazy arguments: We use the syntax defined here.
"return" in perlfunc: We extend the definition of return given here.