This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Lvalue subroutines: implicit and explicit assignment =head1 VERSION Maintainer: James Mastros <[EMAIL PROTECTED]> Date: 24 Aug 2000 Version: 1 Mailing List: [EMAIL PROTECTED] Number: 149 Status: Developing =head1 ABSTRACT 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. =head1 DESCRIPTION =head2 Implicit Assignment 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 C<%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 B<variable>, and then assign to that variable. If the expression cannot be evaluated to that point, (for example, C<$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 C<Object::foo> above, the code C<$obj-E<gt>foo = 42;> should result in this process: =over 3 =item 1. C<Object::foo> is called Object::foo($obj); =item 2. The arguments are processed in accordance with the parameter list of foo: %inner = %$obj; =item 3. C<Object::foo> runs =item 4. C<Object::foo> returns. $temp = lazy $inner{foo} # = $obj->{foo} =item 5. The assignment is preformed. $temp = 42 =item 6. The lazy expression is partially evaluated. $temp => $obj->{foo} =item 7. The (real) assignment is preformed. $obj->{foo} = 42; =back 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. =head2 Explicit Assignment 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 C<: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 C<mode($foo) = 3;> executes by calling mode with %self = %$foo and $mode = 3. The code C<mode($foo) = qw(3 4 5)> has the same effect, since C<qw(3 4 5)> is it's lengh in scalar context. The code C<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 C<mode($foo)++> results in a call to C<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 C<local()>ize or C<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. =head2 Miscellany A subroutine may be marked as being in error to call in a lvalue context by specifying a C<:nonlvalue> attribute on it. This prevents it from being called as an implicit lvalue function. =head1 REFERENCES 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 C<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. L<perlfunc/return>: We extend the definition of return given here.
