develooper Front page | perl.perl5.porters | Postings from June 2013

painting the lvalue list subroutine syntax bikeshed

David Nicol
June 20, 2013 17:37
painting the lvalue list subroutine syntax bikeshed
Message ID:
On Thu, Jun 20, 2013 at 6:05 AM, Paul LeoNerd <> wrote:
> On Thu, 20 Jun 2013 00:14:53 -0500
> David Nicol <> wrote:
>> This set of use cases never needed lvalue subroutines. It has
>> additional calling conventions
>> that have remained unchanged for a very long time, although &slice has
>> to return a
>> reference to a tied array to do anything interesting:
>>    @{slice @array, 2,4} = qw/new elements go here/;
> And how is that any different from implementing lvalue scalar accessors
> with
>    ${ $self->nameref } = "My new name";
> ?

It isn't, at one level. That's how we used to have to do it. Closer
in, it's different because it provides list context instead of scalar
context.  Which is something that has to be done early, because it
affects what the comma means:

bash-3.2$ perl -le '$x = (11,22,33); print $x'
bash-3.2$ perl -le '($x) = (11,22,33); print $x'

A reductio ad absurdam argument against the feature would list the
various problems, run
out of fingers and toes, and cry "Absurd!"

At compile time, either a decoration would be always needed, or the
subroutine signature would have to state that it's a
list-context-imposer. What I was meaning last night was, since a
decoration would be required anyway, keeping circumfix curlies
prefixed by at-sign works fine and isn't new.

> Yes it -can- be done, but there's the neatness of syntax issue.

after a touch of experimentation, I'm not sure it can be done without
tieing the referenced array. I can't just return [$x,$y,$z] as that
gives copies, and returning [\($x,$y,$z)] doesn't
work either because there's no simple way to dereference them.

I want
        sub xyz :lvalue_list{ ( $x,$y,$z ) }
        xyz = (11,22,33);

and the best I can do is

        sub xyz { \($x,$y,$z) }
           my @rvals = (11,22,33);
           foreach ( xyz() ){
               $$_ = shift @rvals

so how should it work? I like to imagine that my preference is for
macros, so something that could wind up looking like a
list-context-imposing l-value subroutine would really be a macro that
expanded into a parenthesized list of the terms, like how qw// works,
but setting that up
would be a lot more complicated than returning ($x,$y,$z) from a
subroutine marked :lvalue.

How does the subroutine know its called in lvalue context?  What if
the subroutine sometimes returns scalars and sometimes lists?
Insisting that array-context-imposers have their own attribute instead
takes care of the second one, but what if such a sub is called
as a scalar r-value?

Maybe if there was a syntax that was the inverse of the backslash
before parentheses operator, that would essentially map $$_ over the
list argument, but unlike map it could be used on a LHS.

         sub xyz { \($x,$y,$z) }
         @\(xyz()) = (11,22,33);  # I'm pretty sure that's new syntax

>> Also, a fancy accessor method that sets with either an arg or when
>> used on a LHS could
>> be built around a trivial scalar tie. Untested implementation below:
> ...
>> package Accessor::Lvalue::Bisyntactical::Retval;
>> sub TIESCALAR { shift; bless [@_] }
>> sub FETCH { $_[0]->[0] }
>> sub STORE { $_[0]->[1]->($_[1]) }
>> 1;
> That's -basically- what Sentinel's pureperl fallback implementation
> does, when it doesn't have the neater Magic-powered XS version.

Yay Sentinel!  After sending that I realized I should have made the
FETCH side a closure too, to defer it. Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About