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

When writing a function with a & prototype like this:

sub foo(&@) { my $code = shift; # whatever ... }
how come when using it, this works:
foo {$_ =~ /foo/} $a, $b, $c;
but this doesn't:
foo({$_ =~ /foo/} $a, $b, $c);

I found a few references searching Google but no explanation that satisfies me. After all, I can call built-ins either way, e.g., this works:

my @x = grep({$_ =~ /foo/} @list);
Nothing in the Camel book either unless I just can't find it. I need enlightenment.

Replies are listed 'Best First'.
Re: & function prototypes and parens
by demerphq (Chancellor) on Feb 08, 2003 at 14:13 UTC
    Prototypes are a hack. There are a bunch of keyword behaviours that just arent implemented for user functions, even with prototypes. But you do know that
    foo(sub {$_ =~ /foo/}, $a, $b, $c);
    works right?

    --- demerphq
    my friends call me, usually because I'm late....

      I was aware that works. I just thought there'd be an explanation for why the other doesn't work when it does work with built-ins. Off the top of my head I can't think of anything else a built-in function can do that I can't. But maybe I'm distinguishing between functions and keywords when such a distinction really doesn't exist internally?

      Semi-enlightened. Thanks.

        The problem is that perls many little idiosyncracies make it difficult to generalize the behaviour of all the built ins. print is another exaple of a keyword whose behaviour cannot be emulated by a user defined function. As are all of the keywords which return undef when passed to prototype.

        As I said before prototypes are a hack. So not all of the special behaviour of map/grep is provided by the prototype. My guess is that this has to do with the issues related to providing complete map or print like behaviour to generalized subs. Too many rules are violated by these procedures for it to be worthwhile to support it except in very special cases. Consider that you didnt cover all the ways that map can be called:

        print map { "foo $_" } @list; print map({"foo $_"} @list); print map "foo $_", @list; print map("foo $_", @list); print map(sub { "foo $_" },@list); # this doesnt do what you think....
        The last one is an example of the troubles that come with map's handling. It parses as
        print map { sub { "foo $_" } } @list;
        which frankly would seem to be an odd interpretation for a user generated function. Luckily we are trained from the get go to treat map as an unusal keyword.

        --- demerphq
        my friends call me, usually because I'm late....

Re: & function prototypes and parens
by tall_man (Parson) on Feb 09, 2003 at 01:30 UTC
    I'm not sure if you found this one yet, but this article by Tom Christiansen is a great reference on perl prototypes and how they can go wrong. (IMHOP, prototypes are a horrible hack and I can't imagine a case where I would use them at all.)

      Good article. Thanks. The only time I've ever wanted to use them is to get the ability to pass a sub reference in as a bare block, ala grep, sort, map, etc. Tom's article leaves them for another time but it's good nonetheless.