Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

More Lvalue Subs - Double-Barreled Closures

by Zaxo (Archbishop)
on Sep 12, 2003 at 04:54 UTC ( #290924=perlmeditation: print w/replies, xml ) Need Help??

Still exploring what can be done with lvalue subs in closures, I came to realize that the trinary operator is also an lvalue. It may be used as a switch for access to different cloistered lexicals. Consider

{ my ($foo,@foo); sub foo () :lvalue { wantarray ? @foo : $foo; } }
foo becomes the accessor for both the scalar and the array. The ordinary rules of context apply:
foo = 'Flintstone'; (foo) = qw/Fred Wilma Pebbles/; # Hmmm, odd bug, the lines following demonstrate what works # print scalar(foo), ', ', $_, $/ for foo; print join ' & ', foo; print ' ', scalar(foo),$/;
More complicated practices are possible. The scalar might be a coderef, to be called on the array.

Something special can happen in void context, by using a defined wantarray ? : ; term in the accessor, though the options are limited by each term's need to be an lvalue. Here a scalar closure is undefined by being called in void context:

{ my $foo; sub foo () :lvalue { defined wantarray ? $foo : undef $foo; } }
This is just exploration, not part of a project. What can you think of to do with it?

After Compline,

Replies are listed 'Best First'.
Re: More Lvalue Subs - Double-Barreled Closures
by Abigail-II (Bishop) on Sep 12, 2003 at 08:35 UTC
    print scalar(foo), ', ', $_, $/ for foo;

    I can't get that to work in any version of Perl I have here. It doesn't print anything at all in 5.6.0, and from 5.6.1 up to bleadperl, it prints:

    Use of uninitialized value in print at cl line 16. Flintstone,

    : lvalue was introduced in 5.6.0, so trying older versions of Perl doesn't make sense.

    However, if I change the line to

    print scalar(foo), ', ', $_, $/ for my @a = foo;

    I get the expected:

    Flintstone, Fred Flintstone, Wilma Flintstone, Pebbles

    It's the lvalue that messes up. Consider the reduced case:

    my @foo = qw /one two three/; sub foo () : lvalue {@foo} print for foo; __END__ Use of uninitialized value in print at /tmp/bug line 9

    But removing the ': lvalue' prints the content of the array. I'll perlbug it.


Re: More Lvalue Subs - Double-Barreled Closures
by Anonymous Monk on Sep 12, 2003 at 06:29 UTC
    I came to realize that the trinary operator is also an lvalue
    How can an operator be a value? btw, your snippet only prints "Flintstone," (the for somehow does not trigger list context).
      The ability to use the trinary operator as an Lvalue is documented in Programming Perl (the Camel book). "You can assign to the conditional operator if both the second and third arguments are legal lvalues (meaning that you can assign to them):" The book also adds the following caviet, "This is not necessarily guaranteed to contribute to the readability of the program. But it can be used to create some cool entries in an Obfuscated Perl contest."

      I just wanted to take a second to illustrate in simpler terms (so that people like me can understand) how to use the trinary operator as an lvalue. Consider the following example:

      my $waypoint = 'N43.4589 W112.9443'; my $latitude; my $longitude; foreach ( split / /, $waypoint ) { ( /^[NnSs]/ ) ? $latitude : $longitude = $_; }

      What this accomplishes is letting the program's logic decide which variable to assign a value to. In the above example, $waypoint could contain latitude first, or longitude first, delimeted by a space. It doesn't matter which one comes first in the string, $latitude and $longitude get assigned the proper half of the value based on the evaluation of the regexp /^[nNsS]/ (which implies latitude, whereas [wWeE] would imply longitude, but we just made the assumption that if it's not latitude, it has to be longitude).

      This is a simple example of using the trinary operator as an lvalue, but it opens the door for a lot of cool things. Zaxo reasoned his way into a pretty cool use. If you really want to create some unreadable code, try nesting trinaries both as lvalues and rvalues in the same expression. It gets ugly fast, and takes a pencil and paper to be able to figure out what is being assigned to, and what is being assigned to it.


      "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://290924]
Approved by belg4mit
Front-paged by BrowserUk
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (8)
As of 2018-10-16 08:30 GMT
Find Nodes?
    Voting Booth?
    When I need money for a bigger acquisition, I usually ...

    Results (83 votes). Check out past polls.