Understanding VARARGS!

I don't think I fully understand varargs. First up I get an error in ReplPad when I try and specify a basic example:

>> ints: func [i [integer! <...>]][collect [while [not tail? i] [keep take i]]]
** Script Error: Failure on bad value (no additional info): <...>

(I checked the tests to see if it was still the right syntax)

Trying on an older version, this works:

>> ints: func [i [integer! <...>]][collect [while [not tail? i][keep take i]]]
== make action! [[i return:] [...]]

>> probe ints 1 2 3 | 4 5
[1 2 3]
== 5

But if I switch to hard quoting, it ignores the type:

>> ints: func [:i [integer! <...>]][collect [while [not tail? i][keep take i]]]
== make action! [[:i return:] [...]]

>> probe ints 1 2 3 | 4 5
ⓘ Note: use WHY for error information
** Script Error: ints does not allow bar! for its i argument

(I don't see a test for hard quoting in this way)

Soft quoting gets closer to what I'm looking for—at least using the expression barrier, but bombs on the wrong type:

>> ints: func ['i [integer! <...>]][collect [while [not tail? i][keep take i]]]  
== make action! [['i return:] [...]]

>> ints 1 2 3 | 4.0 5                                                           
== 5

>> ints 1 2 3 4.0 5   
** Script Error: ints does not allow decimal! for its i argument

I think I'm getting into trouble because I'm trying to do something like this:

>> ints: func [:i [any-value! <...>] d [decimal!]][collect [probe while [match [integer!] first i][keep take i]]]
== make action! [[:i d return:] [...]]

>> probe ints 1 2 3 4.0 5                                                                                         
** Script Error: ints does not allow integer! for its d argument

It is now <variadic>... because <...> is a TUPLE! under our current rules, similar to a...b

If you believe it should be legal to say </foo to call < with a refinement, or <.foo to field select out of <, then <...> being a tuple makes sense.

But if I switch to hard quoting, it ignores the type:

>> ints: func [:i [integer! <...>]][collect [while [not tail? i][keep take i]]]
== make action! [[:i return:] [...]]

Hard quoting is now 'param due to my seemingly logical belief that :param is more semiotic for suggesting "can be escaped with a colon at the callsite". I discuss that maybe ':param is better for "escapable quotable"

Soft quoting gets closer to what I'm looking for, at least using the expression barrier, but bombs on the wrong type:

COMMA! has replaced | as the expression barrier.

ints: func [:i [any-value! <...>] d [decimal!]]

Variadics always take from the end, no matter where you put them. This function would expect a decimal parameter as its first argument.

** Script Error: ints does not allow decimal! for its i argument

A typed variadic parameter doesn't discern the lookahead from TAKE-ing in terms of being constrained to types. This is why I will sometimes separate out a 'look [<opt> any-value! <variadic>] parameter used for looking, so that the variables that do the TAKE-ing can remain typed.

ints: func ['look [<opt> any-value! <variadic>] 'i [integer! <variadic>]] [
    collect [while [integer? first look] [keep take i]]
]

>> x: ints 1 2 3 4.0
== 4.0

>> x
== [1 2 3]

Variadics are old, and haven't gone through much review, to pare back their weird design to something maybe more fitting to their common uses.

Ugh, just realised I was looking at hostilefork/ren-c tests, my bad. Not quite sure how I got there.

I understand the dicey nature of peering out ahead (see also, EVALUATION question), but there seems a potential to quoted variadics vs. non-quoted that is currently unrealised. Perhaps they should be two different concerns.

  • Quoted variadics wouldn't necessarily need to be last

  • Is fixed in scope based purely on type

  • Value could be handled as a block instead of a pseudotype

Could use flags that would throw an error if used in conjunction with a non-quoted arg:

any-nums: func [
    'values [<any> integer! decimal!]
    other-arg [non-number!]
][
    true = block? values
]

any-nums 1 2 3 <thing>
any-nums <thing>

some-nums: func [
    'values [<some> integer! decimal!]
    other-arg [non-number!]
][
    true = block? values
]

some-nums 1 2 3 <thing>

One example of where the tradeoff was made between "what someone could write themselves with a variadic interface" vs. "what you endorse as a parameter convention", see <skip>:

Skippable Arguments

We can make that tradeoff for other things too...since there's not too much abstractly stopping you from using a PARSE rule as your parameter gathering mode. You just have to only go forwards.

For the moment, the main thing is to cover the mechanics. Some of the questions are agonizingly detailed... this one comes to mind :-/

But I'd like to see the parameter gathering not fully baked in, to the point where people can hack on something FUNC-like to give features like your <some> and <any> above, or to add <skip> if it didn't exist already...