smart-matching and sub funhouse

Bad timing: now that smart-matching is under scrutiny, I've started to have fun writing Perl like this:

use signatures;
use Path::Class;

file( 'file.txt' ) ~~ sub ($f) {
   say $f->basename;
   say $f->slurp;
};

This style and syntax is reminiscent of Python's with and Ruby's do, and, for this use case in particular, feels a bit more natural to me than right-to-left, functional-style Perl5:

map { say $_->slurp } file( 'file.txt');

I was just wondering if anyone likes them Perl served like tha'.

Thinking of an alternative, but similar syntax, a year or so ago I forked Perl 5.13.x and patched it trying to make it take sub { } as a method call. Things didn't work as I expected as I'm a Perl5 internals noob, it was a really hot Madrid summer afternoon and I had a higher-than-usual dead brain cell count, but the idea was to be able to call closures on objects:

my $f = file( 'ah-ha' );
$f -> sub {
    say $_->basename . ' = ' . $_->slurp;
};

Which probably could work nicely on native types too:

( 1..10 ) -> sub { ... };  # same as sub{ ... }->( 1..10 );
@arr -> sub { ... }; # sub{ ... }->( @arr );
%hash -> sub { ... }; 
"string" -> sub { ... };

The insignificant white-space before and after the arrow makes it even more expressive.

This is not a proposal, Perl6 already that covered: 'ponty-blocks' come to mind, which even drops sub altogether. But it sure feels like something that could make quite easily into Perl5 without causing a lot of grief.

4 Comments

None of that feels Perlish to me.

for my $f ( file 'file.txt' ) {
   say $f->slurp;
}

You can already call subs as methods, but to avoid confusion with a method called "sub", you need to wrap them in a scalar deref:

file('file.txt')->${\sub ($f) {
    say $f->slurp;
}};

Although you could perform this in Perl 6:

open 'file.txt' ~~ -> $f {
    say $f.slurp;
}

This would be more Perl6ish and similar to Aristotle's Perl 5 example:

given open 'file.txt' -> $f {
    say $f.slurp;
}

Or even this:

given open 'file.txt' {
    say .slurp;
}

I should note though that those examples are just for comparison. If you actually only have a single method call in your block and aren't performing exception handling, it's much simpler:

say open('file.txt').slurp;

Leave a comment

About rodrigolive

user-pic Perl and all things considered