http://www.perlmonks.org?node_id=424788


in reply to Re^5: Experimenting with Lvalue Subs
in thread Experimenting with Lvalue Subs

I'd prefer not supporting applying local to :lvalue subs over requiring them to return an lvalue.

Requiring that a second routine be written in order to even look at the rvalue is ugly. But even uglier is forcing all such 'set this' operations to create an lvalue.

Consider an object that interfaces to some 'thing' outside the process.

99% of the time, when someone writes $obj->Prop= $value; they won't be using local with it. But the design requires that even in those 99% of cases, the 'set' method must not only create a dummy variable, but it must query the external 'thing' to initialize this dummy lvalue just in case local is being used.

I'd like to be able to write lvalue-only methods. And I'd like to write 'set' methods that don't directly store their rvalue argument(s) anywhere.

I like the blurring of methods and member variables, so I don't mind that someone might try to use my lvalue-only method in a non-assignment scenario. I'd just throw an exception for such. So $obj->Prop= $value; can return $value even if $obj has no way to query the external 'thing' to ask it what its Prop currently is. So writing $value= $obj->Prop; can throw an exception.

So I think local should produce code nearly identical to:

my $temp= $obj->Prop; $obj= $newValue; ... $obj->Prop= $temp;

and support local well w/o forcing the "return an lvalue" design which has preventing from ever want to use :lvalue in Perl5 and sounds like it will do that same for me in Perl6.

- tye        

Replies are listed 'Best First'.
Re^7: Experimenting with Lvalue Subs (trade-offs)
by fergal (Chaplain) on Jan 25, 2005 at 06:38 UTC
    Other problems:

    How would this work in the proposed scheme?

    sub double { $_[0] *= 2; } double($o->foo);

    Also currently

    $o->foo+ *= 2;
    calls foo() once whereas it would need to call twice in the proposed scheme.

      Yes, for the rare cases, it increases the number of calls. For the common cases, it can reduce the number of calls and complexity.

      But this brings me back to my original suggestion, which was to leave :lvalue alone and provide :sassign (s=scalar) and :aassign (a=array since both 'list' and 'left' start with 'l') alternatives that make the easy stuff easy (and faster) but may not support the rare stuff (and, obviously, wouldn't support flipping between scalar and list contexts at run time).

      Though you could still support general lvalue emulation for :sassign. For example, when an :sassign is used in an lvalue context other than a simple assignment (and perhaps a few other optimized cases), create a single closure that basicly curries the 'get' part of the method call and give this closure magic which means that assignments to it call it with the value to be assigned as the only parameter.1

      So authors can choose to write 'set' routines in one piece instead of two while allowing their users to use assignment statements while Perl can automatically create a light-weight 'tied' closure only if the user uses the lvalue in a more complicated fashion.

      But those who prefer to write 'set' methods in two pieces can optimize for the complex cases using :lvalue.

      - tye        

      1 I don't know if such makes sense for :aassign cases in Perl6 (it wouldn't in Perl5 because lists get flattened and supporting flattening of :aassign looks like a mine field to me).

        Actually I think your :sassign idea is implementable now using attributes. When you hit a sub with that attr you just need to whip it out and replace it with a sub that returns a tie which calls the original with the extra lvalue argument. Obviously you'd not be happy with the implementation but it would be worth doing just to be able to play with your sassign idea and see if you like it.

        Yes, for the rare cases, it increases the number of calls. For the common cases, it can reduce the number of calls and complexity.
        Increasing the number of calls is not just an efficiency issue, it's potentially a correctness issue, calling twice when previously we called once could do something nasty.