Perl6: variable number of arguments to function/subroutine












9















I want to be able to run a function with a variable number of parameters in Perl6, but after reading through https://docs.perl6.org/language/functions#Arguments I don't see how it can be done. I see numerous links for other languages, and a warning that "Questions with similar titles have frequently been downvoted" but I don't see this anywhere in the documentation or StackOverflow.



I want to do something like this:



some-test($v1, $v2)


or



some-test($v3)


but not have a separate function using multi for each



How can I construct a Perl6 subroutine which will accept a variable number of strings?










share|improve this question























  • So $v3 is a different value to $v1?

    – Scimon
    Feb 15 at 15:52











  • @Scimon all the variables given to the function/subroutine should be independent, so yes, $v3 should be different from $v1

    – con
    Feb 15 at 15:56
















9















I want to be able to run a function with a variable number of parameters in Perl6, but after reading through https://docs.perl6.org/language/functions#Arguments I don't see how it can be done. I see numerous links for other languages, and a warning that "Questions with similar titles have frequently been downvoted" but I don't see this anywhere in the documentation or StackOverflow.



I want to do something like this:



some-test($v1, $v2)


or



some-test($v3)


but not have a separate function using multi for each



How can I construct a Perl6 subroutine which will accept a variable number of strings?










share|improve this question























  • So $v3 is a different value to $v1?

    – Scimon
    Feb 15 at 15:52











  • @Scimon all the variables given to the function/subroutine should be independent, so yes, $v3 should be different from $v1

    – con
    Feb 15 at 15:56














9












9








9








I want to be able to run a function with a variable number of parameters in Perl6, but after reading through https://docs.perl6.org/language/functions#Arguments I don't see how it can be done. I see numerous links for other languages, and a warning that "Questions with similar titles have frequently been downvoted" but I don't see this anywhere in the documentation or StackOverflow.



I want to do something like this:



some-test($v1, $v2)


or



some-test($v3)


but not have a separate function using multi for each



How can I construct a Perl6 subroutine which will accept a variable number of strings?










share|improve this question














I want to be able to run a function with a variable number of parameters in Perl6, but after reading through https://docs.perl6.org/language/functions#Arguments I don't see how it can be done. I see numerous links for other languages, and a warning that "Questions with similar titles have frequently been downvoted" but I don't see this anywhere in the documentation or StackOverflow.



I want to do something like this:



some-test($v1, $v2)


or



some-test($v3)


but not have a separate function using multi for each



How can I construct a Perl6 subroutine which will accept a variable number of strings?







perl6






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Feb 15 at 15:30









concon

1,0961820




1,0961820













  • So $v3 is a different value to $v1?

    – Scimon
    Feb 15 at 15:52











  • @Scimon all the variables given to the function/subroutine should be independent, so yes, $v3 should be different from $v1

    – con
    Feb 15 at 15:56



















  • So $v3 is a different value to $v1?

    – Scimon
    Feb 15 at 15:52











  • @Scimon all the variables given to the function/subroutine should be independent, so yes, $v3 should be different from $v1

    – con
    Feb 15 at 15:56

















So $v3 is a different value to $v1?

– Scimon
Feb 15 at 15:52





So $v3 is a different value to $v1?

– Scimon
Feb 15 at 15:52













@Scimon all the variables given to the function/subroutine should be independent, so yes, $v3 should be different from $v1

– con
Feb 15 at 15:56





@Scimon all the variables given to the function/subroutine should be independent, so yes, $v3 should be different from $v1

– con
Feb 15 at 15:56












3 Answers
3






active

oldest

votes


















7














TL;DR You're asking about variadic functions.1 Simple use is simple. Some P6 features, most notably positional and named arguments, and variadic destructuring, add some wrinkles. Also, see the other answers which are very helpful too.




variable number of arguments




Simple use of a simple variadic function:



sub variadic (|args) { say args .elems }
variadic(); # 0
variadic('1'); # 1
variadic('1', '2'); # 2


A |foo parameter slurps up all remaining arguments into a Capture bound to sigilless identifier foo:



sub variadic ($a, @b, %c, |others) { say others[0] }
variadic 1, [2,3], (:foo), 4, [5,6], (:bar); # 4


In the above example the others parameter "slurps"1 up the last three listed arguments starting with the 4.



Variadic variations



Things aren't always simple:



variadic(1, 2);       # 2 -- works but args are Ints
variadic(:foo,:bar); # 0 -- where did :foo, :bar go?
variadic((:foo)); # 1 -- works; arg is Pair (:foo)
variadic((1, 2)); # 1 -- works; arg is List (1,2)


In the rest of this answer I explain:




  • Constraining arguments, eg ensuring they're all strings.


  • Positional vs named arguments; **@foo and *%foo


  • Variadic positionals destructuring; +@foo and *@foo



Constraining arguments




variable number of strings




You can impose any constraints you want on slurped arguments by using a where clause. (Which you can in turn package into a subset if you want.)



For example, to constrain all the arguments to be of type Str:



sub variadic (|args where .all ~~ Str) { say args .elems }
variadic(); # 0
variadic('1'); # 1
variadic('1', '2'); # 2
variadic(1); # Constraint type check failed



Positional vs named arguments; **@foo and *%foo



P6 supports both positional and named arguments.



Using |foo in a signature always captures all remaining arguments, both positional and named:



sub slurps-into-WHAT (|args) { say WHAT args }
slurps-into-WHAT(); # (Capture)


A Capture stores positional arguments in an internal list accessible via positional subscripting (i.e. args[...]) and named arguments in a hash accessible via associative subscripting (i.e. args<...> or args{...}):



sub variadic (|args) { say " {args[1]} {args<named2>}" }
variadic('pos0', 'pos1', named1 => 42, named2 => 99); # pos1 99


Sometimes it's preferable to collect just named args, or just positional ones, or to collect both but in separate parameters.



To collect named args, use a parameter of the form *%foo (one asterisk prefix and a hash arg):



sub variadic-for-nameds (*%nameds) { say %nameds }
variadic-for-nameds(:foo, :bar); # {bar => True, foo => True}


(Note that all methods collect named args in this way even if their signature doesn't explicitly say so.2)



To collect positional args, use a parameter of the form **@foo (two asterisk prefix immediately followed by an array arg):



sub variadic-for-positionals (**@positionals) { say @positionals }
variadic-for-positionals(1, 2, 3); # [1 2 3]


Variadic positionals destructuring; +@foo and *@foo



P6 provides a range of non-variadic argument destructuring features.



The first variadic positionals destructuring parameter form is +@foo. This has exactly the same effect as **@foo except in one case; if the variadic parameter gets just a single argument, and that argument is a list or array, then the parameter is bound to the content of that list or array, stripping away the list/array container:



sub variadic-plus (+@positionals) { say @positionals }
variadic-plus(1,2,3); # says same as for **@positionals
variadic-plus(1); # says same as for **@positionals
variadic-plus([1]); # [1] -- instead of [[1]]
variadic-plus((1,2,3)); # [1 2 3] -- instead of [(1 2 3)]


The +@foo form was introduced to support the "single arg rule". It's used by core devs writing built ins. Users may wish to use it when they want the same behavior.



The other variadic positionals destructuring form is *@foo. It does the same thing as +@foo in that it extracts the content from list or array container args and throws the container away. But it's much more aggressive:




  • It does this for all arguments.


  • If an argument is a list rather than an array ((...) rather than [...]) then it descends into that list and recursively repeats the exercise if an element of the list is itself another inner list or array.



Thus:



sub variadic-star (*@positionals) { say @positionals }
variadic-star((1,2),[3,4]); # [1 2 3 4]
variadic-star((1,2),(3,4,(5,6,(7,8)))); # [1 2 3 4 5 6 7 8]
variadic-star((1,2),(3,4,[5,6,(7,8)])); # [1 2 3 4 5 6 (7 8)]


(Note how it stripped the container from the [5,6,(7,8)] array but did not descend into it.)



One final thing; are there variadic named destructuring parameters? You tell me.3



Bonus section: foo(...) vs foo (...)



(I included this bonus section in the hope it heads off confusion. If this section is itself confusing, just ignore it.)



Routine calls can be written with or without parentheses around their list of arguments and they mean the same thing. The opening parenthesis must follow the routine name immediately, without intervening whitespace:



sub foo  (|args)  { say args[0] }
foo 'a', 'b'; # a
foo('a', 'b'); # a


(This rule only applies to the routine call, between the routine name and its arguments. It does not apply to the routine declaration, between the routine name and its parameters. For the latter, the declaration, you can leave no space or use space as I have above with sub foo (|args) and it makes no difference.)



If you insert whitespace between the foo and the opening parenthesis in a call you're writing something different:



foo  ('a', 'b'); # (a b)


That calls foo with one argument, the one list ('a', 'b') in contrast to foo('a', 'b') which calls foo with two arguments, the two values inside the parentheses.



The following calls foo with two arguments, both of which are lists:



foo ('a', 'b', 'c'),  ('d', 'e', 'f'); # (a b c)


You may nest parentheses:



foo(  ('a', 'b', 'c'),  ('d', 'e', 'f')  )    ; # (a b c)
foo (('a', 'b', 'c'), ('d', 'e', 'f')) ; # ((a b c) (d e f))
foo( (('a', 'b', 'c'), ('d', 'e', 'f')) ) ; # ((a b c) (d e f))


The latter two foo calls get one argument, the one list ( ('a', 'b', 'c'), ('d', 'e', 'f') ) (that happens to contain two inner lists).



Footnotes



1 The standard industry term for this is a variadic function. At the time of writing this answer, the Rakudo P6 compiler uses the industry standard term ("variadic") in error messages but the official P6 doc tends to use the word "slurpy" instead of "variadic" and talks of "slurping up arguments".



2 Methods always have an implicit variadic named parameter called %_ if one is not explicitly specified:



say .signature given my method foo {} # (Mu: *%_)


3 The P6 language and/or the Rakudo P6 compiler currently allows parameters to be written in the form +%foo and **%foo. It doesn't really make sense to have variadic nameds destructuring. Perhaps that explains why both these forms do insane things:




  • **%foo appears to be indistinguishable from %foo.


  • +%foo appears to be indistinguishable from **@foo except for using the identifier %foo instead of @foo. The object bound to %foo is an Array!







share|improve this answer





















  • 1





    what is the purpose of the ** and +@? These don't appear to exponentiate and add

    – con
    Feb 15 at 17:48






  • 1





    Answer rewritten. Please LMK if it makes sense and answers your questions.

    – raiph
    Feb 16 at 23:08






  • 1





    thanks for writing all of that, I'll get to reading it soon. I really appreciate all of the work that you put in to that answer!

    – con
    Feb 18 at 16:02



















7














If you just want to be able to take 1 or 2 values then the easiest way is to mark the second value as optional :



sub some-test( $v1, $v2? ) { ... }


Or you can define a default value :



sub some-test( $v1, $v2="default" ) { ... }


Or if you want any number of values (1 or more) you can use a slurpy with a where clause :



sub some-test( *@v where *.elems > 0 ) { ... }





share|improve this answer
























  • this fails with Constraint type check failed in binding to parameter '@v'; expected anonymous constraint to be met but got Array ($["a", "b"]) :-(

    – con
    Feb 15 at 16:11











  • Can you share the subroutine definition you used? $["a","b"] should match the where clause of *.elems > 0 (as it's got 2 elements).

    – Scimon
    Feb 15 at 16:15











  • sub some-test (*@v where *.elems < 0) { for @v -> $v { put $v } } my $x = 'a'; my $y = 'b'; some-test($x, $y);

    – con
    Feb 15 at 16:35











  • So you are testing elems < 0 which is true arrays with negative elements in. Instead of you test for elems > 0 then you won't accept an empty array but will accept others

    – Scimon
    Feb 15 at 16:41











  • Another option to get at least one value is to use sub some-test($v1, *@rest) { }

    – moritz
    Feb 16 at 13:04



















7














You can use signature destructuring



sub some-test(*@all [$first, *@rest]) { ... } # must have 1 or more parameters





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54712440%2fperl6-variable-number-of-arguments-to-function-subroutine%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    7














    TL;DR You're asking about variadic functions.1 Simple use is simple. Some P6 features, most notably positional and named arguments, and variadic destructuring, add some wrinkles. Also, see the other answers which are very helpful too.




    variable number of arguments




    Simple use of a simple variadic function:



    sub variadic (|args) { say args .elems }
    variadic(); # 0
    variadic('1'); # 1
    variadic('1', '2'); # 2


    A |foo parameter slurps up all remaining arguments into a Capture bound to sigilless identifier foo:



    sub variadic ($a, @b, %c, |others) { say others[0] }
    variadic 1, [2,3], (:foo), 4, [5,6], (:bar); # 4


    In the above example the others parameter "slurps"1 up the last three listed arguments starting with the 4.



    Variadic variations



    Things aren't always simple:



    variadic(1, 2);       # 2 -- works but args are Ints
    variadic(:foo,:bar); # 0 -- where did :foo, :bar go?
    variadic((:foo)); # 1 -- works; arg is Pair (:foo)
    variadic((1, 2)); # 1 -- works; arg is List (1,2)


    In the rest of this answer I explain:




    • Constraining arguments, eg ensuring they're all strings.


    • Positional vs named arguments; **@foo and *%foo


    • Variadic positionals destructuring; +@foo and *@foo



    Constraining arguments




    variable number of strings




    You can impose any constraints you want on slurped arguments by using a where clause. (Which you can in turn package into a subset if you want.)



    For example, to constrain all the arguments to be of type Str:



    sub variadic (|args where .all ~~ Str) { say args .elems }
    variadic(); # 0
    variadic('1'); # 1
    variadic('1', '2'); # 2
    variadic(1); # Constraint type check failed



    Positional vs named arguments; **@foo and *%foo



    P6 supports both positional and named arguments.



    Using |foo in a signature always captures all remaining arguments, both positional and named:



    sub slurps-into-WHAT (|args) { say WHAT args }
    slurps-into-WHAT(); # (Capture)


    A Capture stores positional arguments in an internal list accessible via positional subscripting (i.e. args[...]) and named arguments in a hash accessible via associative subscripting (i.e. args<...> or args{...}):



    sub variadic (|args) { say " {args[1]} {args<named2>}" }
    variadic('pos0', 'pos1', named1 => 42, named2 => 99); # pos1 99


    Sometimes it's preferable to collect just named args, or just positional ones, or to collect both but in separate parameters.



    To collect named args, use a parameter of the form *%foo (one asterisk prefix and a hash arg):



    sub variadic-for-nameds (*%nameds) { say %nameds }
    variadic-for-nameds(:foo, :bar); # {bar => True, foo => True}


    (Note that all methods collect named args in this way even if their signature doesn't explicitly say so.2)



    To collect positional args, use a parameter of the form **@foo (two asterisk prefix immediately followed by an array arg):



    sub variadic-for-positionals (**@positionals) { say @positionals }
    variadic-for-positionals(1, 2, 3); # [1 2 3]


    Variadic positionals destructuring; +@foo and *@foo



    P6 provides a range of non-variadic argument destructuring features.



    The first variadic positionals destructuring parameter form is +@foo. This has exactly the same effect as **@foo except in one case; if the variadic parameter gets just a single argument, and that argument is a list or array, then the parameter is bound to the content of that list or array, stripping away the list/array container:



    sub variadic-plus (+@positionals) { say @positionals }
    variadic-plus(1,2,3); # says same as for **@positionals
    variadic-plus(1); # says same as for **@positionals
    variadic-plus([1]); # [1] -- instead of [[1]]
    variadic-plus((1,2,3)); # [1 2 3] -- instead of [(1 2 3)]


    The +@foo form was introduced to support the "single arg rule". It's used by core devs writing built ins. Users may wish to use it when they want the same behavior.



    The other variadic positionals destructuring form is *@foo. It does the same thing as +@foo in that it extracts the content from list or array container args and throws the container away. But it's much more aggressive:




    • It does this for all arguments.


    • If an argument is a list rather than an array ((...) rather than [...]) then it descends into that list and recursively repeats the exercise if an element of the list is itself another inner list or array.



    Thus:



    sub variadic-star (*@positionals) { say @positionals }
    variadic-star((1,2),[3,4]); # [1 2 3 4]
    variadic-star((1,2),(3,4,(5,6,(7,8)))); # [1 2 3 4 5 6 7 8]
    variadic-star((1,2),(3,4,[5,6,(7,8)])); # [1 2 3 4 5 6 (7 8)]


    (Note how it stripped the container from the [5,6,(7,8)] array but did not descend into it.)



    One final thing; are there variadic named destructuring parameters? You tell me.3



    Bonus section: foo(...) vs foo (...)



    (I included this bonus section in the hope it heads off confusion. If this section is itself confusing, just ignore it.)



    Routine calls can be written with or without parentheses around their list of arguments and they mean the same thing. The opening parenthesis must follow the routine name immediately, without intervening whitespace:



    sub foo  (|args)  { say args[0] }
    foo 'a', 'b'; # a
    foo('a', 'b'); # a


    (This rule only applies to the routine call, between the routine name and its arguments. It does not apply to the routine declaration, between the routine name and its parameters. For the latter, the declaration, you can leave no space or use space as I have above with sub foo (|args) and it makes no difference.)



    If you insert whitespace between the foo and the opening parenthesis in a call you're writing something different:



    foo  ('a', 'b'); # (a b)


    That calls foo with one argument, the one list ('a', 'b') in contrast to foo('a', 'b') which calls foo with two arguments, the two values inside the parentheses.



    The following calls foo with two arguments, both of which are lists:



    foo ('a', 'b', 'c'),  ('d', 'e', 'f'); # (a b c)


    You may nest parentheses:



    foo(  ('a', 'b', 'c'),  ('d', 'e', 'f')  )    ; # (a b c)
    foo (('a', 'b', 'c'), ('d', 'e', 'f')) ; # ((a b c) (d e f))
    foo( (('a', 'b', 'c'), ('d', 'e', 'f')) ) ; # ((a b c) (d e f))


    The latter two foo calls get one argument, the one list ( ('a', 'b', 'c'), ('d', 'e', 'f') ) (that happens to contain two inner lists).



    Footnotes



    1 The standard industry term for this is a variadic function. At the time of writing this answer, the Rakudo P6 compiler uses the industry standard term ("variadic") in error messages but the official P6 doc tends to use the word "slurpy" instead of "variadic" and talks of "slurping up arguments".



    2 Methods always have an implicit variadic named parameter called %_ if one is not explicitly specified:



    say .signature given my method foo {} # (Mu: *%_)


    3 The P6 language and/or the Rakudo P6 compiler currently allows parameters to be written in the form +%foo and **%foo. It doesn't really make sense to have variadic nameds destructuring. Perhaps that explains why both these forms do insane things:




    • **%foo appears to be indistinguishable from %foo.


    • +%foo appears to be indistinguishable from **@foo except for using the identifier %foo instead of @foo. The object bound to %foo is an Array!







    share|improve this answer





















    • 1





      what is the purpose of the ** and +@? These don't appear to exponentiate and add

      – con
      Feb 15 at 17:48






    • 1





      Answer rewritten. Please LMK if it makes sense and answers your questions.

      – raiph
      Feb 16 at 23:08






    • 1





      thanks for writing all of that, I'll get to reading it soon. I really appreciate all of the work that you put in to that answer!

      – con
      Feb 18 at 16:02
















    7














    TL;DR You're asking about variadic functions.1 Simple use is simple. Some P6 features, most notably positional and named arguments, and variadic destructuring, add some wrinkles. Also, see the other answers which are very helpful too.




    variable number of arguments




    Simple use of a simple variadic function:



    sub variadic (|args) { say args .elems }
    variadic(); # 0
    variadic('1'); # 1
    variadic('1', '2'); # 2


    A |foo parameter slurps up all remaining arguments into a Capture bound to sigilless identifier foo:



    sub variadic ($a, @b, %c, |others) { say others[0] }
    variadic 1, [2,3], (:foo), 4, [5,6], (:bar); # 4


    In the above example the others parameter "slurps"1 up the last three listed arguments starting with the 4.



    Variadic variations



    Things aren't always simple:



    variadic(1, 2);       # 2 -- works but args are Ints
    variadic(:foo,:bar); # 0 -- where did :foo, :bar go?
    variadic((:foo)); # 1 -- works; arg is Pair (:foo)
    variadic((1, 2)); # 1 -- works; arg is List (1,2)


    In the rest of this answer I explain:




    • Constraining arguments, eg ensuring they're all strings.


    • Positional vs named arguments; **@foo and *%foo


    • Variadic positionals destructuring; +@foo and *@foo



    Constraining arguments




    variable number of strings




    You can impose any constraints you want on slurped arguments by using a where clause. (Which you can in turn package into a subset if you want.)



    For example, to constrain all the arguments to be of type Str:



    sub variadic (|args where .all ~~ Str) { say args .elems }
    variadic(); # 0
    variadic('1'); # 1
    variadic('1', '2'); # 2
    variadic(1); # Constraint type check failed



    Positional vs named arguments; **@foo and *%foo



    P6 supports both positional and named arguments.



    Using |foo in a signature always captures all remaining arguments, both positional and named:



    sub slurps-into-WHAT (|args) { say WHAT args }
    slurps-into-WHAT(); # (Capture)


    A Capture stores positional arguments in an internal list accessible via positional subscripting (i.e. args[...]) and named arguments in a hash accessible via associative subscripting (i.e. args<...> or args{...}):



    sub variadic (|args) { say " {args[1]} {args<named2>}" }
    variadic('pos0', 'pos1', named1 => 42, named2 => 99); # pos1 99


    Sometimes it's preferable to collect just named args, or just positional ones, or to collect both but in separate parameters.



    To collect named args, use a parameter of the form *%foo (one asterisk prefix and a hash arg):



    sub variadic-for-nameds (*%nameds) { say %nameds }
    variadic-for-nameds(:foo, :bar); # {bar => True, foo => True}


    (Note that all methods collect named args in this way even if their signature doesn't explicitly say so.2)



    To collect positional args, use a parameter of the form **@foo (two asterisk prefix immediately followed by an array arg):



    sub variadic-for-positionals (**@positionals) { say @positionals }
    variadic-for-positionals(1, 2, 3); # [1 2 3]


    Variadic positionals destructuring; +@foo and *@foo



    P6 provides a range of non-variadic argument destructuring features.



    The first variadic positionals destructuring parameter form is +@foo. This has exactly the same effect as **@foo except in one case; if the variadic parameter gets just a single argument, and that argument is a list or array, then the parameter is bound to the content of that list or array, stripping away the list/array container:



    sub variadic-plus (+@positionals) { say @positionals }
    variadic-plus(1,2,3); # says same as for **@positionals
    variadic-plus(1); # says same as for **@positionals
    variadic-plus([1]); # [1] -- instead of [[1]]
    variadic-plus((1,2,3)); # [1 2 3] -- instead of [(1 2 3)]


    The +@foo form was introduced to support the "single arg rule". It's used by core devs writing built ins. Users may wish to use it when they want the same behavior.



    The other variadic positionals destructuring form is *@foo. It does the same thing as +@foo in that it extracts the content from list or array container args and throws the container away. But it's much more aggressive:




    • It does this for all arguments.


    • If an argument is a list rather than an array ((...) rather than [...]) then it descends into that list and recursively repeats the exercise if an element of the list is itself another inner list or array.



    Thus:



    sub variadic-star (*@positionals) { say @positionals }
    variadic-star((1,2),[3,4]); # [1 2 3 4]
    variadic-star((1,2),(3,4,(5,6,(7,8)))); # [1 2 3 4 5 6 7 8]
    variadic-star((1,2),(3,4,[5,6,(7,8)])); # [1 2 3 4 5 6 (7 8)]


    (Note how it stripped the container from the [5,6,(7,8)] array but did not descend into it.)



    One final thing; are there variadic named destructuring parameters? You tell me.3



    Bonus section: foo(...) vs foo (...)



    (I included this bonus section in the hope it heads off confusion. If this section is itself confusing, just ignore it.)



    Routine calls can be written with or without parentheses around their list of arguments and they mean the same thing. The opening parenthesis must follow the routine name immediately, without intervening whitespace:



    sub foo  (|args)  { say args[0] }
    foo 'a', 'b'; # a
    foo('a', 'b'); # a


    (This rule only applies to the routine call, between the routine name and its arguments. It does not apply to the routine declaration, between the routine name and its parameters. For the latter, the declaration, you can leave no space or use space as I have above with sub foo (|args) and it makes no difference.)



    If you insert whitespace between the foo and the opening parenthesis in a call you're writing something different:



    foo  ('a', 'b'); # (a b)


    That calls foo with one argument, the one list ('a', 'b') in contrast to foo('a', 'b') which calls foo with two arguments, the two values inside the parentheses.



    The following calls foo with two arguments, both of which are lists:



    foo ('a', 'b', 'c'),  ('d', 'e', 'f'); # (a b c)


    You may nest parentheses:



    foo(  ('a', 'b', 'c'),  ('d', 'e', 'f')  )    ; # (a b c)
    foo (('a', 'b', 'c'), ('d', 'e', 'f')) ; # ((a b c) (d e f))
    foo( (('a', 'b', 'c'), ('d', 'e', 'f')) ) ; # ((a b c) (d e f))


    The latter two foo calls get one argument, the one list ( ('a', 'b', 'c'), ('d', 'e', 'f') ) (that happens to contain two inner lists).



    Footnotes



    1 The standard industry term for this is a variadic function. At the time of writing this answer, the Rakudo P6 compiler uses the industry standard term ("variadic") in error messages but the official P6 doc tends to use the word "slurpy" instead of "variadic" and talks of "slurping up arguments".



    2 Methods always have an implicit variadic named parameter called %_ if one is not explicitly specified:



    say .signature given my method foo {} # (Mu: *%_)


    3 The P6 language and/or the Rakudo P6 compiler currently allows parameters to be written in the form +%foo and **%foo. It doesn't really make sense to have variadic nameds destructuring. Perhaps that explains why both these forms do insane things:




    • **%foo appears to be indistinguishable from %foo.


    • +%foo appears to be indistinguishable from **@foo except for using the identifier %foo instead of @foo. The object bound to %foo is an Array!







    share|improve this answer





















    • 1





      what is the purpose of the ** and +@? These don't appear to exponentiate and add

      – con
      Feb 15 at 17:48






    • 1





      Answer rewritten. Please LMK if it makes sense and answers your questions.

      – raiph
      Feb 16 at 23:08






    • 1





      thanks for writing all of that, I'll get to reading it soon. I really appreciate all of the work that you put in to that answer!

      – con
      Feb 18 at 16:02














    7












    7








    7







    TL;DR You're asking about variadic functions.1 Simple use is simple. Some P6 features, most notably positional and named arguments, and variadic destructuring, add some wrinkles. Also, see the other answers which are very helpful too.




    variable number of arguments




    Simple use of a simple variadic function:



    sub variadic (|args) { say args .elems }
    variadic(); # 0
    variadic('1'); # 1
    variadic('1', '2'); # 2


    A |foo parameter slurps up all remaining arguments into a Capture bound to sigilless identifier foo:



    sub variadic ($a, @b, %c, |others) { say others[0] }
    variadic 1, [2,3], (:foo), 4, [5,6], (:bar); # 4


    In the above example the others parameter "slurps"1 up the last three listed arguments starting with the 4.



    Variadic variations



    Things aren't always simple:



    variadic(1, 2);       # 2 -- works but args are Ints
    variadic(:foo,:bar); # 0 -- where did :foo, :bar go?
    variadic((:foo)); # 1 -- works; arg is Pair (:foo)
    variadic((1, 2)); # 1 -- works; arg is List (1,2)


    In the rest of this answer I explain:




    • Constraining arguments, eg ensuring they're all strings.


    • Positional vs named arguments; **@foo and *%foo


    • Variadic positionals destructuring; +@foo and *@foo



    Constraining arguments




    variable number of strings




    You can impose any constraints you want on slurped arguments by using a where clause. (Which you can in turn package into a subset if you want.)



    For example, to constrain all the arguments to be of type Str:



    sub variadic (|args where .all ~~ Str) { say args .elems }
    variadic(); # 0
    variadic('1'); # 1
    variadic('1', '2'); # 2
    variadic(1); # Constraint type check failed



    Positional vs named arguments; **@foo and *%foo



    P6 supports both positional and named arguments.



    Using |foo in a signature always captures all remaining arguments, both positional and named:



    sub slurps-into-WHAT (|args) { say WHAT args }
    slurps-into-WHAT(); # (Capture)


    A Capture stores positional arguments in an internal list accessible via positional subscripting (i.e. args[...]) and named arguments in a hash accessible via associative subscripting (i.e. args<...> or args{...}):



    sub variadic (|args) { say " {args[1]} {args<named2>}" }
    variadic('pos0', 'pos1', named1 => 42, named2 => 99); # pos1 99


    Sometimes it's preferable to collect just named args, or just positional ones, or to collect both but in separate parameters.



    To collect named args, use a parameter of the form *%foo (one asterisk prefix and a hash arg):



    sub variadic-for-nameds (*%nameds) { say %nameds }
    variadic-for-nameds(:foo, :bar); # {bar => True, foo => True}


    (Note that all methods collect named args in this way even if their signature doesn't explicitly say so.2)



    To collect positional args, use a parameter of the form **@foo (two asterisk prefix immediately followed by an array arg):



    sub variadic-for-positionals (**@positionals) { say @positionals }
    variadic-for-positionals(1, 2, 3); # [1 2 3]


    Variadic positionals destructuring; +@foo and *@foo



    P6 provides a range of non-variadic argument destructuring features.



    The first variadic positionals destructuring parameter form is +@foo. This has exactly the same effect as **@foo except in one case; if the variadic parameter gets just a single argument, and that argument is a list or array, then the parameter is bound to the content of that list or array, stripping away the list/array container:



    sub variadic-plus (+@positionals) { say @positionals }
    variadic-plus(1,2,3); # says same as for **@positionals
    variadic-plus(1); # says same as for **@positionals
    variadic-plus([1]); # [1] -- instead of [[1]]
    variadic-plus((1,2,3)); # [1 2 3] -- instead of [(1 2 3)]


    The +@foo form was introduced to support the "single arg rule". It's used by core devs writing built ins. Users may wish to use it when they want the same behavior.



    The other variadic positionals destructuring form is *@foo. It does the same thing as +@foo in that it extracts the content from list or array container args and throws the container away. But it's much more aggressive:




    • It does this for all arguments.


    • If an argument is a list rather than an array ((...) rather than [...]) then it descends into that list and recursively repeats the exercise if an element of the list is itself another inner list or array.



    Thus:



    sub variadic-star (*@positionals) { say @positionals }
    variadic-star((1,2),[3,4]); # [1 2 3 4]
    variadic-star((1,2),(3,4,(5,6,(7,8)))); # [1 2 3 4 5 6 7 8]
    variadic-star((1,2),(3,4,[5,6,(7,8)])); # [1 2 3 4 5 6 (7 8)]


    (Note how it stripped the container from the [5,6,(7,8)] array but did not descend into it.)



    One final thing; are there variadic named destructuring parameters? You tell me.3



    Bonus section: foo(...) vs foo (...)



    (I included this bonus section in the hope it heads off confusion. If this section is itself confusing, just ignore it.)



    Routine calls can be written with or without parentheses around their list of arguments and they mean the same thing. The opening parenthesis must follow the routine name immediately, without intervening whitespace:



    sub foo  (|args)  { say args[0] }
    foo 'a', 'b'; # a
    foo('a', 'b'); # a


    (This rule only applies to the routine call, between the routine name and its arguments. It does not apply to the routine declaration, between the routine name and its parameters. For the latter, the declaration, you can leave no space or use space as I have above with sub foo (|args) and it makes no difference.)



    If you insert whitespace between the foo and the opening parenthesis in a call you're writing something different:



    foo  ('a', 'b'); # (a b)


    That calls foo with one argument, the one list ('a', 'b') in contrast to foo('a', 'b') which calls foo with two arguments, the two values inside the parentheses.



    The following calls foo with two arguments, both of which are lists:



    foo ('a', 'b', 'c'),  ('d', 'e', 'f'); # (a b c)


    You may nest parentheses:



    foo(  ('a', 'b', 'c'),  ('d', 'e', 'f')  )    ; # (a b c)
    foo (('a', 'b', 'c'), ('d', 'e', 'f')) ; # ((a b c) (d e f))
    foo( (('a', 'b', 'c'), ('d', 'e', 'f')) ) ; # ((a b c) (d e f))


    The latter two foo calls get one argument, the one list ( ('a', 'b', 'c'), ('d', 'e', 'f') ) (that happens to contain two inner lists).



    Footnotes



    1 The standard industry term for this is a variadic function. At the time of writing this answer, the Rakudo P6 compiler uses the industry standard term ("variadic") in error messages but the official P6 doc tends to use the word "slurpy" instead of "variadic" and talks of "slurping up arguments".



    2 Methods always have an implicit variadic named parameter called %_ if one is not explicitly specified:



    say .signature given my method foo {} # (Mu: *%_)


    3 The P6 language and/or the Rakudo P6 compiler currently allows parameters to be written in the form +%foo and **%foo. It doesn't really make sense to have variadic nameds destructuring. Perhaps that explains why both these forms do insane things:




    • **%foo appears to be indistinguishable from %foo.


    • +%foo appears to be indistinguishable from **@foo except for using the identifier %foo instead of @foo. The object bound to %foo is an Array!







    share|improve this answer















    TL;DR You're asking about variadic functions.1 Simple use is simple. Some P6 features, most notably positional and named arguments, and variadic destructuring, add some wrinkles. Also, see the other answers which are very helpful too.




    variable number of arguments




    Simple use of a simple variadic function:



    sub variadic (|args) { say args .elems }
    variadic(); # 0
    variadic('1'); # 1
    variadic('1', '2'); # 2


    A |foo parameter slurps up all remaining arguments into a Capture bound to sigilless identifier foo:



    sub variadic ($a, @b, %c, |others) { say others[0] }
    variadic 1, [2,3], (:foo), 4, [5,6], (:bar); # 4


    In the above example the others parameter "slurps"1 up the last three listed arguments starting with the 4.



    Variadic variations



    Things aren't always simple:



    variadic(1, 2);       # 2 -- works but args are Ints
    variadic(:foo,:bar); # 0 -- where did :foo, :bar go?
    variadic((:foo)); # 1 -- works; arg is Pair (:foo)
    variadic((1, 2)); # 1 -- works; arg is List (1,2)


    In the rest of this answer I explain:




    • Constraining arguments, eg ensuring they're all strings.


    • Positional vs named arguments; **@foo and *%foo


    • Variadic positionals destructuring; +@foo and *@foo



    Constraining arguments




    variable number of strings




    You can impose any constraints you want on slurped arguments by using a where clause. (Which you can in turn package into a subset if you want.)



    For example, to constrain all the arguments to be of type Str:



    sub variadic (|args where .all ~~ Str) { say args .elems }
    variadic(); # 0
    variadic('1'); # 1
    variadic('1', '2'); # 2
    variadic(1); # Constraint type check failed



    Positional vs named arguments; **@foo and *%foo



    P6 supports both positional and named arguments.



    Using |foo in a signature always captures all remaining arguments, both positional and named:



    sub slurps-into-WHAT (|args) { say WHAT args }
    slurps-into-WHAT(); # (Capture)


    A Capture stores positional arguments in an internal list accessible via positional subscripting (i.e. args[...]) and named arguments in a hash accessible via associative subscripting (i.e. args<...> or args{...}):



    sub variadic (|args) { say " {args[1]} {args<named2>}" }
    variadic('pos0', 'pos1', named1 => 42, named2 => 99); # pos1 99


    Sometimes it's preferable to collect just named args, or just positional ones, or to collect both but in separate parameters.



    To collect named args, use a parameter of the form *%foo (one asterisk prefix and a hash arg):



    sub variadic-for-nameds (*%nameds) { say %nameds }
    variadic-for-nameds(:foo, :bar); # {bar => True, foo => True}


    (Note that all methods collect named args in this way even if their signature doesn't explicitly say so.2)



    To collect positional args, use a parameter of the form **@foo (two asterisk prefix immediately followed by an array arg):



    sub variadic-for-positionals (**@positionals) { say @positionals }
    variadic-for-positionals(1, 2, 3); # [1 2 3]


    Variadic positionals destructuring; +@foo and *@foo



    P6 provides a range of non-variadic argument destructuring features.



    The first variadic positionals destructuring parameter form is +@foo. This has exactly the same effect as **@foo except in one case; if the variadic parameter gets just a single argument, and that argument is a list or array, then the parameter is bound to the content of that list or array, stripping away the list/array container:



    sub variadic-plus (+@positionals) { say @positionals }
    variadic-plus(1,2,3); # says same as for **@positionals
    variadic-plus(1); # says same as for **@positionals
    variadic-plus([1]); # [1] -- instead of [[1]]
    variadic-plus((1,2,3)); # [1 2 3] -- instead of [(1 2 3)]


    The +@foo form was introduced to support the "single arg rule". It's used by core devs writing built ins. Users may wish to use it when they want the same behavior.



    The other variadic positionals destructuring form is *@foo. It does the same thing as +@foo in that it extracts the content from list or array container args and throws the container away. But it's much more aggressive:




    • It does this for all arguments.


    • If an argument is a list rather than an array ((...) rather than [...]) then it descends into that list and recursively repeats the exercise if an element of the list is itself another inner list or array.



    Thus:



    sub variadic-star (*@positionals) { say @positionals }
    variadic-star((1,2),[3,4]); # [1 2 3 4]
    variadic-star((1,2),(3,4,(5,6,(7,8)))); # [1 2 3 4 5 6 7 8]
    variadic-star((1,2),(3,4,[5,6,(7,8)])); # [1 2 3 4 5 6 (7 8)]


    (Note how it stripped the container from the [5,6,(7,8)] array but did not descend into it.)



    One final thing; are there variadic named destructuring parameters? You tell me.3



    Bonus section: foo(...) vs foo (...)



    (I included this bonus section in the hope it heads off confusion. If this section is itself confusing, just ignore it.)



    Routine calls can be written with or without parentheses around their list of arguments and they mean the same thing. The opening parenthesis must follow the routine name immediately, without intervening whitespace:



    sub foo  (|args)  { say args[0] }
    foo 'a', 'b'; # a
    foo('a', 'b'); # a


    (This rule only applies to the routine call, between the routine name and its arguments. It does not apply to the routine declaration, between the routine name and its parameters. For the latter, the declaration, you can leave no space or use space as I have above with sub foo (|args) and it makes no difference.)



    If you insert whitespace between the foo and the opening parenthesis in a call you're writing something different:



    foo  ('a', 'b'); # (a b)


    That calls foo with one argument, the one list ('a', 'b') in contrast to foo('a', 'b') which calls foo with two arguments, the two values inside the parentheses.



    The following calls foo with two arguments, both of which are lists:



    foo ('a', 'b', 'c'),  ('d', 'e', 'f'); # (a b c)


    You may nest parentheses:



    foo(  ('a', 'b', 'c'),  ('d', 'e', 'f')  )    ; # (a b c)
    foo (('a', 'b', 'c'), ('d', 'e', 'f')) ; # ((a b c) (d e f))
    foo( (('a', 'b', 'c'), ('d', 'e', 'f')) ) ; # ((a b c) (d e f))


    The latter two foo calls get one argument, the one list ( ('a', 'b', 'c'), ('d', 'e', 'f') ) (that happens to contain two inner lists).



    Footnotes



    1 The standard industry term for this is a variadic function. At the time of writing this answer, the Rakudo P6 compiler uses the industry standard term ("variadic") in error messages but the official P6 doc tends to use the word "slurpy" instead of "variadic" and talks of "slurping up arguments".



    2 Methods always have an implicit variadic named parameter called %_ if one is not explicitly specified:



    say .signature given my method foo {} # (Mu: *%_)


    3 The P6 language and/or the Rakudo P6 compiler currently allows parameters to be written in the form +%foo and **%foo. It doesn't really make sense to have variadic nameds destructuring. Perhaps that explains why both these forms do insane things:




    • **%foo appears to be indistinguishable from %foo.


    • +%foo appears to be indistinguishable from **@foo except for using the identifier %foo instead of @foo. The object bound to %foo is an Array!








    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 16 at 23:06

























    answered Feb 15 at 17:00









    raiphraiph

    11.1k22138




    11.1k22138








    • 1





      what is the purpose of the ** and +@? These don't appear to exponentiate and add

      – con
      Feb 15 at 17:48






    • 1





      Answer rewritten. Please LMK if it makes sense and answers your questions.

      – raiph
      Feb 16 at 23:08






    • 1





      thanks for writing all of that, I'll get to reading it soon. I really appreciate all of the work that you put in to that answer!

      – con
      Feb 18 at 16:02














    • 1





      what is the purpose of the ** and +@? These don't appear to exponentiate and add

      – con
      Feb 15 at 17:48






    • 1





      Answer rewritten. Please LMK if it makes sense and answers your questions.

      – raiph
      Feb 16 at 23:08






    • 1





      thanks for writing all of that, I'll get to reading it soon. I really appreciate all of the work that you put in to that answer!

      – con
      Feb 18 at 16:02








    1




    1





    what is the purpose of the ** and +@? These don't appear to exponentiate and add

    – con
    Feb 15 at 17:48





    what is the purpose of the ** and +@? These don't appear to exponentiate and add

    – con
    Feb 15 at 17:48




    1




    1





    Answer rewritten. Please LMK if it makes sense and answers your questions.

    – raiph
    Feb 16 at 23:08





    Answer rewritten. Please LMK if it makes sense and answers your questions.

    – raiph
    Feb 16 at 23:08




    1




    1





    thanks for writing all of that, I'll get to reading it soon. I really appreciate all of the work that you put in to that answer!

    – con
    Feb 18 at 16:02





    thanks for writing all of that, I'll get to reading it soon. I really appreciate all of the work that you put in to that answer!

    – con
    Feb 18 at 16:02













    7














    If you just want to be able to take 1 or 2 values then the easiest way is to mark the second value as optional :



    sub some-test( $v1, $v2? ) { ... }


    Or you can define a default value :



    sub some-test( $v1, $v2="default" ) { ... }


    Or if you want any number of values (1 or more) you can use a slurpy with a where clause :



    sub some-test( *@v where *.elems > 0 ) { ... }





    share|improve this answer
























    • this fails with Constraint type check failed in binding to parameter '@v'; expected anonymous constraint to be met but got Array ($["a", "b"]) :-(

      – con
      Feb 15 at 16:11











    • Can you share the subroutine definition you used? $["a","b"] should match the where clause of *.elems > 0 (as it's got 2 elements).

      – Scimon
      Feb 15 at 16:15











    • sub some-test (*@v where *.elems < 0) { for @v -> $v { put $v } } my $x = 'a'; my $y = 'b'; some-test($x, $y);

      – con
      Feb 15 at 16:35











    • So you are testing elems < 0 which is true arrays with negative elements in. Instead of you test for elems > 0 then you won't accept an empty array but will accept others

      – Scimon
      Feb 15 at 16:41











    • Another option to get at least one value is to use sub some-test($v1, *@rest) { }

      – moritz
      Feb 16 at 13:04
















    7














    If you just want to be able to take 1 or 2 values then the easiest way is to mark the second value as optional :



    sub some-test( $v1, $v2? ) { ... }


    Or you can define a default value :



    sub some-test( $v1, $v2="default" ) { ... }


    Or if you want any number of values (1 or more) you can use a slurpy with a where clause :



    sub some-test( *@v where *.elems > 0 ) { ... }





    share|improve this answer
























    • this fails with Constraint type check failed in binding to parameter '@v'; expected anonymous constraint to be met but got Array ($["a", "b"]) :-(

      – con
      Feb 15 at 16:11











    • Can you share the subroutine definition you used? $["a","b"] should match the where clause of *.elems > 0 (as it's got 2 elements).

      – Scimon
      Feb 15 at 16:15











    • sub some-test (*@v where *.elems < 0) { for @v -> $v { put $v } } my $x = 'a'; my $y = 'b'; some-test($x, $y);

      – con
      Feb 15 at 16:35











    • So you are testing elems < 0 which is true arrays with negative elements in. Instead of you test for elems > 0 then you won't accept an empty array but will accept others

      – Scimon
      Feb 15 at 16:41











    • Another option to get at least one value is to use sub some-test($v1, *@rest) { }

      – moritz
      Feb 16 at 13:04














    7












    7








    7







    If you just want to be able to take 1 or 2 values then the easiest way is to mark the second value as optional :



    sub some-test( $v1, $v2? ) { ... }


    Or you can define a default value :



    sub some-test( $v1, $v2="default" ) { ... }


    Or if you want any number of values (1 or more) you can use a slurpy with a where clause :



    sub some-test( *@v where *.elems > 0 ) { ... }





    share|improve this answer













    If you just want to be able to take 1 or 2 values then the easiest way is to mark the second value as optional :



    sub some-test( $v1, $v2? ) { ... }


    Or you can define a default value :



    sub some-test( $v1, $v2="default" ) { ... }


    Or if you want any number of values (1 or more) you can use a slurpy with a where clause :



    sub some-test( *@v where *.elems > 0 ) { ... }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Feb 15 at 15:59









    ScimonScimon

    1,8771311




    1,8771311













    • this fails with Constraint type check failed in binding to parameter '@v'; expected anonymous constraint to be met but got Array ($["a", "b"]) :-(

      – con
      Feb 15 at 16:11











    • Can you share the subroutine definition you used? $["a","b"] should match the where clause of *.elems > 0 (as it's got 2 elements).

      – Scimon
      Feb 15 at 16:15











    • sub some-test (*@v where *.elems < 0) { for @v -> $v { put $v } } my $x = 'a'; my $y = 'b'; some-test($x, $y);

      – con
      Feb 15 at 16:35











    • So you are testing elems < 0 which is true arrays with negative elements in. Instead of you test for elems > 0 then you won't accept an empty array but will accept others

      – Scimon
      Feb 15 at 16:41











    • Another option to get at least one value is to use sub some-test($v1, *@rest) { }

      – moritz
      Feb 16 at 13:04



















    • this fails with Constraint type check failed in binding to parameter '@v'; expected anonymous constraint to be met but got Array ($["a", "b"]) :-(

      – con
      Feb 15 at 16:11











    • Can you share the subroutine definition you used? $["a","b"] should match the where clause of *.elems > 0 (as it's got 2 elements).

      – Scimon
      Feb 15 at 16:15











    • sub some-test (*@v where *.elems < 0) { for @v -> $v { put $v } } my $x = 'a'; my $y = 'b'; some-test($x, $y);

      – con
      Feb 15 at 16:35











    • So you are testing elems < 0 which is true arrays with negative elements in. Instead of you test for elems > 0 then you won't accept an empty array but will accept others

      – Scimon
      Feb 15 at 16:41











    • Another option to get at least one value is to use sub some-test($v1, *@rest) { }

      – moritz
      Feb 16 at 13:04

















    this fails with Constraint type check failed in binding to parameter '@v'; expected anonymous constraint to be met but got Array ($["a", "b"]) :-(

    – con
    Feb 15 at 16:11





    this fails with Constraint type check failed in binding to parameter '@v'; expected anonymous constraint to be met but got Array ($["a", "b"]) :-(

    – con
    Feb 15 at 16:11













    Can you share the subroutine definition you used? $["a","b"] should match the where clause of *.elems > 0 (as it's got 2 elements).

    – Scimon
    Feb 15 at 16:15





    Can you share the subroutine definition you used? $["a","b"] should match the where clause of *.elems > 0 (as it's got 2 elements).

    – Scimon
    Feb 15 at 16:15













    sub some-test (*@v where *.elems < 0) { for @v -> $v { put $v } } my $x = 'a'; my $y = 'b'; some-test($x, $y);

    – con
    Feb 15 at 16:35





    sub some-test (*@v where *.elems < 0) { for @v -> $v { put $v } } my $x = 'a'; my $y = 'b'; some-test($x, $y);

    – con
    Feb 15 at 16:35













    So you are testing elems < 0 which is true arrays with negative elements in. Instead of you test for elems > 0 then you won't accept an empty array but will accept others

    – Scimon
    Feb 15 at 16:41





    So you are testing elems < 0 which is true arrays with negative elements in. Instead of you test for elems > 0 then you won't accept an empty array but will accept others

    – Scimon
    Feb 15 at 16:41













    Another option to get at least one value is to use sub some-test($v1, *@rest) { }

    – moritz
    Feb 16 at 13:04





    Another option to get at least one value is to use sub some-test($v1, *@rest) { }

    – moritz
    Feb 16 at 13:04











    7














    You can use signature destructuring



    sub some-test(*@all [$first, *@rest]) { ... } # must have 1 or more parameters





    share|improve this answer




























      7














      You can use signature destructuring



      sub some-test(*@all [$first, *@rest]) { ... } # must have 1 or more parameters





      share|improve this answer


























        7












        7








        7







        You can use signature destructuring



        sub some-test(*@all [$first, *@rest]) { ... } # must have 1 or more parameters





        share|improve this answer













        You can use signature destructuring



        sub some-test(*@all [$first, *@rest]) { ... } # must have 1 or more parameters






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Feb 15 at 16:39









        ugexeugexe

        2,017923




        2,017923






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54712440%2fperl6-variable-number-of-arguments-to-function-subroutine%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

            is 'sed' thread safe

            How to make a Squid Proxy server?