Arrow Operator Shenanigans

Out of curiosity, boredom, and some inspiration by the method abuse in Safe::Isa and Object::Remote, I tried the following:

use strict;
use warnings FATAL => 'all';
use feature 'say';

my $split = sub {
    my ( $str, $sep ) = @_;
    return [ split( $sep, $str ) ];
};

my $join = sub {
    my( $arr, $sep ) = @_;
    return join($sep,@$arr);
};

say "Lorem ipsum dolor sit amet"->$split(" ")->$join(":");

my $inc = sub {
    $_[0]++;
};

my $num = 4;
$num->$inc;
$num->$inc;
say $num;

I was mildly surprised that it worked. I was more surprised that I couldn't find a reason for why it worked in the documentation for the Arrow Operator.

edit [ In the comments I was pointed to perldoc perlobj where this behavior is documented. ]

I'm certain coding this way would be a Pretty Bad Idea ( especially as an undocumented language feature ) but it has a sort of appeal; though 70% of the appeal is just the sheer hackery of it with the rest being some theory that chaining may be easier to read than g(f(x)).

16 Comments

It's documented in 'Subroutine References as Methods' in perldoc perlobj:

 You can also use a subroutine reference as a method:
 $file->$sub();
 This is exactly equivalent to writing "$sub->($file)".

so I think it's fine to rely on this behaviour. Might be worth a doc patch for perlop if you had trouble finding the perlobj reference?

This is a very useful syntax for dynamic coding, where the subroutine is created at runtime and then passed around.

chaining may be easier to read than g(f(x)).

FYI, Perl6 has sequencer operators for that:

source() ==> filter() ==> sink()

http://perlcabal.org/syn/S03.html

This sound like an interesting way to do reverse auto-boxing, by writing a module that exports a bunch of these methods as scalar variables, thus making it possible to treat a number of common operations as method calls without needing to wrap the basic scalars or messing with UNIVERSAL.

Has somebody written such a module yet?

Mithaldu, People have (ab)used the roles in Moose::Autobox to produce a similar behavior without actual auto boxing.


package MyArray {
use Moose;
with 'Moose::Autobox::Array';
}

my $array = bless [] => 'MyArray';

$array->push(1, 2, 3);

print $array->join(", ");

Sometimes when I see stuff like this I start to think perhaps we've not even scratched the surface of what Perl5 syntax can really do, and its just long time practice holding us back.

jnap

Thanks, that's similar and interesting. I have to say though i'm not tempted to use it, since it provides little comfort in use, as i still need to touch and modify each variable i want to call methods on.

Looking at #p5p i find mauke did actually make this: https://metacpan.org/pod/Fauxtobox

I don't think a doc patch would be necessary, the link to perlobj is right there, I just failed at finding it.

Bzzzzzzt. :-) If you failed to find it then chances are that others in your position will make the same assumptions about where to look and then likewise fail to find it. That’s a failure of the docs.

I have no idea. Get on IRC and ask mauke? :)

The leading underscore is probably to reduce the chance of variable name collision, would be my guess. --jnap

i saw that and thought, makes sense. then i wondered why i'd never thought of it.

Leave a comment

About Samuel Kaufman

user-pic CTO / Codemonkey, Socialflow.com