http://qs1969.pair.com?node_id=608036

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

Hi all,

I've just stumbled on the impossibility of prototyping a sub that must accept arbitrary number of arguments. Basically, I need something like sub ttt(\@;\@...) where ... is ellipsis, so one or more arrays can be passed by reference. I know that perlsub doesn't say anything about this, but possibly someone heard of a relevant XS hack? Thank you.

( PS. Yes, I surely can sub ttt(@); ttt(\@a,\@b,\@c) but it is not at all as interesting as ttt(@a,@b,@c) )

Replies are listed 'Best First'.
Re: prototypes: so many \@'s?
by BrowserUk (Patriarch) on Apr 03, 2007 at 12:04 UTC
      Still no answer, but thanks++ for the interesting links!
Re: prototypes: so many \@'s?
by Anno (Deacon) on Apr 03, 2007 at 13:52 UTC
    There is no such hack I know of. What I've seen on CPAN (in List::MoreUtils, for instance) is attempts to allow "enough" arguments:
    sub each_array (\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@) {
    That seems to be the dissatisfactory state of the art in this respect.

    Anno

      Indeed. I also found the "enough" syntax, but it looked so wrong that I didn't even dare to ask about it. Thanks++ for the answer anyway.
        I happen to know the author of List::MoreUtils Usenet-wise and I know he'd search far and wide before letting this uglines stand in a module. If there was a better solution, Tassilo would have found it.

        Anno

Re: prototypes: so many \@'s?
by ferreira (Chaplain) on Apr 03, 2007 at 18:01 UTC

    Even if you are aware, maybe it is good to remember: "Don't use prototypes". Except in a very small number of cases of restricted utility (like ($$) prototyped functions used with sort), they don't do what you want (unless you're very weirdo to match the craziness of Perl prototype semantics).

    One example:

    sub foo ($$) { $_[0] + $_[1] } # add two scalar args :) foo(1,2) @a = (1,2); foo(@a); # death !! not enough arguments @b1 = (2); @b2 = (3); foo(@b1,@b2) # 2 !?!? = scalar @b1 + scalar @b2

    And don't take my words. Tom Christiansen said that a long time ago and Damian Conway said more about it in "Perl Best Practices".

    That said, maybe you may get the behavior you want with a module like Params::Validate. See the docs with a special attention to the section on "Callback Validation":

      This particular form of prototype provides a facility that cannot be achieved any other way. Perhaps you should understand what that facility is before handing out old and well worn advice those who already know it.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
Re: prototypes: so many \@'s?
by Moron (Curate) on Apr 03, 2007 at 16:00 UTC
    I tried (@\@) but that accepted any old thing (doh!). perlsub does warn you the prototyping capability is limited!

    You could always roll your own at run-time, something like (untested):

    our %proto = ( '@\@' => sub { return !grep (ref( $_ ) ne 'ARRAY' ), @_ +; }, # ... # proto => sub { enforcement-code } ); sub foo { $proto{ '@\@' }{@_} or die; # followed by "real" code for sub foo }

    -M

    Free your mind

Re: prototypes: so many \@'s?
by agianni (Hermit) on Apr 03, 2007 at 13:33 UTC
    ( PS. Yes, I surely can sub ttt(@); ttt(\@a,\@b,\@c) but it is not at all as interesting as ttt(@a,@b,@c) )

    Nor is it the same thing. The main reason that you should be considering the second option would be if you needed to pass the value of the arrays such that they would not potentially be modified by the subroutine you are calling. If you are not so worried about that possibility and more worried about potentially copying large data structures, the former is your best option.

    Unfortunately, I can't offer any useful advice on the question at hand :)

    perl -e 'split//,q{john hurl, pest caretaker}and(map{print @_[$_]}(joi +n(q{},map{sprintf(qq{%010u},$_)}(2**2*307*4993,5*101*641*5261,7*59*79 +*36997,13*17*71*45131,3**2*67*89*167*181))=~/\d{2}/g));'
      A prototype of (@) is meaningless. It does not force anything because the smallest list is empty: it asks for an argument in list context, not an array.
      I don't think there is a prototype for what you ask, you will probably have to do without (ttt(\@a,\@b,\@c)) and use ref to check that each argument is of the correct type. Trouble is that this is a run-time check not a compile-time check as you get with a prototype.
Re: prototypes: so many \@'s?
by phaylon (Curate) on Apr 03, 2007 at 15:24 UTC
    Basically, I need something like sub ttt(\@;\@...) where ... is ellipsis, so one or more arrays can be passed by reference.

    Why?


    Ordinary morality is for ordinary people. -- Aleister Crowley