tadman has asked for the wisdom of the Perl Monks concerning the following question:

There are, it seems, only a few nodes which speak of lvalue subroutines, such as this, which is surprising since they can be quite useful.

The question is, though, how do you know what context the lvalue subroutine is being called in? Here's a simple example:
my $foo; my $foo_new; sub fooz : lvalue { $foo; } $foo = "Bar"; # Initialization print fooz,"\n"; # Reading fooz = "Foo"; # Assignment print fooz,"\n"; # Reading
Within the subroutine, I'm looking for a mechanism similar to wantarray which can return some information about what side of the assignment the sub is on. Here's what I'd like to be able to do:
my $foo; my $foo_new; sub fooz : lvalue { defined ($foo_new)? $foo_new : (islvalue? $foo_new = $foo : $foo); } $foo = "Bar"; # Initialization print fooz,"\n"; # Reading fooz = "Foo"; # Assignment print fooz,"\n"; # Reading
Here the idea is that any writes go into $foo_new, while the reads come from $foo, unless of course there is a $foo_new, in which case they will read from $foo_new.

This all hinges on their being some sort of hint about what side the sub is appearing on, left or right.

Admittely, this is oversimplified, and in this example there will be issues if one decides to assign 'undef' to fooz(). The code is merely for demonstration purposes.

If there is no mechanism presently, is this kind of thing worth implementing as a patch?

Replies are listed 'Best First'.
Re: Side Context in an 'lvalue' Subroutine
by broquaint (Abbot) on Mar 18, 2002 at 18:58 UTC
    I think the Want module might be exactly what you're looking for.
    HTH

    broquaint

      The Want module is quite interesting, but seems a little awkward in terms of implementation. Here's an example:
      use Want; sub fooz : lvalue { defined ($foo_new)? $foo_new : (want('LVALUE','ASSIGN')? $foo_new = $foo : $foo); }
      Internally, there is a function from the Wait.xs component called 'want_lvalue', which is really all I need. If it were assigned a default parameter value (it relates to stack depth) then it could be used like so:
      use Want; sub fooz : lvalue { defined ($foo_new)? $foo_new : want_lvalue? $foo_new = $foo : $foo); }
      This does seem to be a lot neater, though not currently implemented.

      It just goes to show that CPAN has a module for every occasion. I wouldn't be surprised to see Cheese::Grater.

      Thanks for the tip. It's exactly what I was looking for.
Re: Side Context in an 'lvalue' Subroutine
by Juerd (Abbot) on Mar 18, 2002 at 19:05 UTC

    If there is no mechanism presently, is this kind of thing worth implementing as a patch?

    I don't know if there's an lvalue-sub way of doing that, but you could turn it all around, and not have a function that is an lvalue, but have an lvalue that is a couple of functions!

    That's right, I'm talking about tie.

    package Tie::Fooz; sub TIESCALAR { bless \(my $dummy), $_[0] } sub FETCH { ${ $_[0] } } sub STORE { ${ $_[0] } = $_[1] } package main; tie my $foo, 'Tie::Fooz';
    Unfortunately, I have not a clue what your code should do or why you would want to use a $foo_new, so I couldn't create an equivalent tie. Anyway, STORE serves as your islvalue condition, and FETCH for not islvalue, I think.

    U28geW91IGNhbiBhbGwgcm90MTMgY
    W5kIHBhY2soKS4gQnV0IGRvIHlvdS
    ByZWNvZ25pc2UgQmFzZTY0IHdoZW4
    geW91IHNlZSBpdD8gIC0tIEp1ZXJk
    

      As much as I'm a fan of tie, for this kind of operation it seems to Benchmark abysmally slow, and, additionally, requires a lot of extra effort to impose on a particular scalar. Consider that within an object there may be dozens of variables, each of which would have to be tied independently. Using a single AUTOLOAD lvalue subroutine you could take care of them all, on-demand.

      overload came to mind too, but the assignment ('=') override is a hack at best, though to the credit of the implementor, this is because of Force Majeure, and not lack of initiative or inventiveness.