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


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

You know, when I first read that section of A6, I thought "that's as ugly as anything I've ever seen... eh, I'm sure it'll get changed". Now, around 3 years later, I re-read it, and I think "that's as ugly as anything I've ever seen -- it's gotta get fixed, or we'll be stuck with it". This doesn't match how I think about lvalue subs. It doesn't match how I think of lvalue subs. I think of lvalue subs as a different calling convention from a normal sub -- a view reinforced by that being the way most languages that have them seem to think of them. The way you're doing it seems to match the way perl5 does it. Lvalue subs aren't much used in perl5, and them being annoying to use is one reason for that.

Why not make $foo->bar('baz')='quux'; with a declared method multimethod bar($this: *@lvalues, @rvales :rvalues); does... well, the obvious: makes $this be $foo, @rvalues be ('bar') and @lvalues be ('quux'). IOW, make the lvalues be a special zone (in A6 terms), with no presigil signifier, but only a long name. (I suppose you haven't yet used > (points to the left) for anything in this context, but it'd be confusing, because it comes up rarely, and could be difficult to find in the docs, whereas "rvalue" is somewhat obvious, or at least easier to look up.)

As is normal for multimethods, that body is only called if the call matches it -- that is, it's done in an lvalue context.

One difficulty is in determining the context of the RHS of the assignment. Normally, the context of an assignment is determined by what is being assigned to. This is one of the major reasons in both p5 and p6, the lvalue is evaluated before the rvalue, which is why the lvalue sub can't tell what rvalue is being assigned. This needs an aditional rule, I think, instead of a workaround that keeps information from the programmer when they want it. If the lvalue sub has only a single scalar paramter in the :rvalues zone, then it's in scalar context. Otherwise, it's in list context. (If there are two multimethods that have equally compatable signatures, and one of them would be list context by this rule, and the other scalar, then warn, and do it in list.)


Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

Replies are listed 'Best First'.
Re^3: Experimenting with Lvalue Subs
by TimToady (Parson) on Jan 25, 2005 at 02:11 UTC
    The purpose of an lvalue sub is to return an lvalue.

      Really? I always thought the purpose of an lvalue sub is to let $x->location='over there'; Just Work.

      That's what the user wants, that's what the API designer wants. The rest, nobody wants to see except for the languge theorist. While their needs are sometimes interesting, they shouldn't get in the way of the users and the API designers.


      Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

        Would you also like:
        $x->location++;
        to Just Work? How 'bout:
        my_increment($x->location);
        presuming that the argument is declared rw. And what about:
        $ref = \$x->location; $$ref++;
        and such?

        You've got yer blinders on if you think that's all just "language theory".

        Though it's kind of nice to be accused of being a language theorist for a change. Usually I'm accused of sacrificing theory on the altar of practicality.

        How do you want to make

        local $foo->bar = 'baz';

        work, then? BrowserUk and I are struggling with that elsewhere in the thread, too.

        Larry is right, if you do anything else than return an lvalue from the sub, then this is not really possible. As I said in the other subthread, I suppose validation could be handled inline anyway, but there really is no getting around the fact that an lvalue sub must return an lvalue if you want to support dynamically scoped assignments.

        Makeshifts last the longest.

      Which by the testimony of this thread will be as near useless and unuseable in P6 as they are in p5.


      Examine what is said, not who speaks.
      Silence betokens consent.
      Love the truth but pardon error.
        Then the testimony of this thread is simply wrong. By explicit design, lvalue subs in Perl 6 will be just as usable as variables, which the testimony of this thread does not seem to understand are useful in many more places than just on one side of an = or the other. It's only the writing of lvalue subs that you're carping about, and that will definitely be easier in Perl 6 than in Perl 5. I see no new data here to warrant reopening the case.
Re^3: Experimenting with Lvalue Subs
by theorbtwo (Prior) on Jan 25, 2005 at 02:10 UTC

    As I look more, I begin to see a problem in my plan. It's in the last paragraph of the above, which assumes that we can figure out which of a set of multimethods will be called in any purticular circumstance very early -- it'd require evaluation of the RHS before we determine what context to evaluate the RHS in. It may be neccessary to provide the context of the RHS as an explicit attribute of the method, and disallow having different versions that vary by rvalue context with the same non-rvalue signature.

    The order of evaluation would then go as follows:

    1. Invocant.
    2. LHS arguments
    3. At this point, we determine which of the potentially competeing multimethods to call. If there are none, or more then one with the same goodness, error (possibly not error, but just pick the first or last in the second case).
    4. Determine the context for the RHS.
    5. Evalute the RHS.
    6. Finally, call the actual lvalue method.

    I realize that this makes reverting the value somewhat more complex from the core -- but if the core thinks of the rollback as being a new assignment, and propigates exceptions thrown, it shouldn't be much more difficult. (Note that this is hardly the only place that exceptions can be thrown from nonobvious places.) I think it's far more important to give an interface to lvalue subs that matches the way people think about them.


    Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node). Update: fixed HTML.