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

Consider the following
sub subby(&\@\@) { my ($coderef, $listA, $listB) = @_; my @result; .. logic .. @result; }
I can call this fine using the following -
my @subset = subby { .. logic .. } @A, @B;
However, if I try to call it like this
my @subset = subby { .. logic .. } @A, grep { .. logic .. } @B;
I get this ->
Type of arg 3 to main::subby must be array (not grep iterator) at ./te +st line 36, near "@B;"
This yields the same error
my @subset = subby { .. logic .. } @A, (grep { .. logic .. } @B);
Any ideas on how to get around this?

Replies are listed 'Best First'.
Re: "not grep iterator" error
by Fletch (Bishop) on Sep 09, 2009 at 20:11 UTC

    You can't. A prototype of \@ requires an actual array in that position, not merely something list-y. Quoth perlsub:

    Any backslashed prototype character represents an actual argument that absolutely must start with that character. The value passed as part of @_ will be a reference to the actual argument given in the subroutine call, obtained by applying "\" to that argument.

    Depending on your intent you might get away with (my @new_B = grep { ... } @B) instead (untested), but you'd be better off trying to get cheeky with prototypes and just pass references explicitly (which would mean you'd just need [grep { ... } @B]).

    Update: Added a missing =

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: "not grep iterator" error
by NetWallah (Canon) on Sep 09, 2009 at 20:31 UTC
    This works for me:
    perl -we "use strict; sub subby(&\@\@){print qq|in subby..@{$_[2]};\n| +}; my @x=subby sub{print qq|calling...|},my @c, @{[ grep {/\d/} 0..6] +}"
    OUTPUT:
    in subby..0 1 2 3 4 5 6;

    Basically - encapsulate the "grep" result into something that looks like an array (Make an arrayref and dereference it).

    But, like Fletch said .. do the right thing, and declare it properly.

         Potentia vobiscum ! (Si hoc legere scis nimium eruditionis habes)

      You're right, that does work. However, the reason I was using \@ in my prototype was so that I could modify the list. Copying into and then dereferencing a new list defeats the purpose. What I have ended up doing is using a prototype like this
      sub subby(&\@@)
      Then, I can modify the first list (but only pass it in as @list) and for the second list, I can use grep and friends to produce it, which suits my needs. Thanks

        From what you've said, your function takes a callback and two list, modifies the elements of both lists and returns a third list. Your function is insane.

        ( No, I misunderstood. It only modifies the first array which makes the rest of this post moot. The function is still pretty crazy, though )

        Anyway, you seem to be asking how to create an array of aliases. It's actually possible with little work!

        sub foo(\@) { my ($array) = @_; $_ = uc($_) for @$array; } my @array = qw( foo bar Foo Bar ); foo @{ sub { \@_ }->( grep /^[A-Z]/, @array ) }; print "$_\n" for @array;
        foo bar FOO BAR

        Of course, an array wouldn't normally be used at all.

        sub foo { $_ = uc($_) for @_; } my @array = qw( foo bar Foo Bar ); foo grep /^[A-Z]/, @array; print "$_\n" for @array;
        foo bar FOO BAR