views:

124

answers:

4

Imagine this subroutine:

sub test(&&)
{
    my $cr1 = shift;
    my $cr2 = shift;
    $cr1->();
    $cr2->();
}

I know I can call it like: test(\&sub1,\&sub2), but how can I call it like:

test { print 1 },{ print 2 };

If I say that the subroutine takes only one &, than sending a block will work. I don't know how to make it work with 2.

If I try to run it like that, I get:

Not enough arguments for main::test at script.pl line 38, near "},"

EDIT: is there no way of invoking without sub?

+8  A: 

You can do this:

test(sub { print 1 }, sub { print 2 });
bdonlan
You _have_ to do it like this. Otherwise it will seem to perl like you are trying to pass two hash-refs.
innaM
I want to invoke them without sub. Both of them.
Geo
sub is Perl's way of writing an anonymous subroutine. So either use a ref to a named sub, or an expression that evaluates to one (e.g. variable whose value is a subref), or use an anonymous sub - in the latter case, you will use `sub{}`
DVK
+1 for bdonlan, mostly for TFGITW :)
DVK
@DVK, for _what_?
bdonlan
"the fattest girl in the world" is the commonest meaning I saw. There's also "thank freaking goodness it's the weekend" (polite form). Neither makes a lot of sense to me.
ysth
Fastest Gun In The West :)Meaning, you beat my nearly identical answer by <1 minute, IIRC
DVK
See http://meta.stackoverflow.com/questions/9731/fastest-gun-in-the-west-problem and http://meta.stackoverflow.com/questions/73/is-the-fastest-gun-in-the-west-solved :)
DVK
+1  A: 

I've got the following code in one of my programs:

sub generate($$$$)
{
    my ($paramRef, $waypointCodeRef, $headerRef,
        $debugCodeRef) = @_;
...
   &$headerRef();
...
       my $used = &$waypointCodeRef(\%record);

And I call it with

CreateDB::generate(\%param, \&wayPointCode, \&doHeader, \&debugCode);
Paul Tomblin
+12  A: 

You need to explicitly say

test( sub { print 1 }, sub { print 2 } );

or

test { print 1 } sub { print 2 };

The implicit "sub" is only available for the first argument. http://perldoc.perl.org/perlsub.html#Prototypes:

An & requires an anonymous subroutine, which, if passed as the first argument, does not require the sub keyword or a subsequent comma.

Some things use an extra word in there to fake it:

test { print 1 } against { print 2 };

sub against (&) { $_[0] }
sub test (&@) { ... }

but I've never liked that much.

ysth
So there's no way of achieving this without a `source filter`?
Geo
@Geo: Pretend source filters don't exist. Forget you ever heard of them.
ysth
+1  A: 

If you really want to bend the syntax more then take look at Devel::Declare

Examples of modules that use Devel::Declare:

Full list of modules on CPAN dependant on Devel::Declare can be found via CPANTS

Here is example from Test::Class::Sugar pod:

use Test::Class::Sugar;

testclass exercises Person {
    # Test::Most has been magically included

    startup >> 1 {
        use_ok $test->subject;
    }

    test autonaming {
        is ref($test), 'Test::Person';
    }

    test the naming of parts {
        is $test->current_method, 'test_the_naming_of_parts';
    }

    test multiple assertions >> 2 {
        is ref($test), 'Test::Person';
        is $test->current_method, 'test_multiple_assertions';
    }
}

Test::Class->runtests;


And here is something sexy from PerlX::MethodCallWithBlock pod:

use PerlX::MethodCallWithBlock;

Foo->bar(1, 2, 3) {
  say "and a block";
};


Devel::Declare is a much more robust and saner way of contorting your Perl code compared to using a source filter like Filter::Simple.

Here is a video from its author which may help a bit more.

/I3az/

draegtun
What makes this work? Source filters?
Geo
From the Devel::Declare docs: "Devel::Declare can install subroutines called declarators which locally take over Perl's parser, allowing the creation of new syntax." I don't really understand how it works, but it is not a source filter.
Dave Sherohman