Typed varargs

I would like to define a function with a variable number of typed arguments. In particular I would like to overload the + operator in this way

function Base.:+(a::MyType, (c, args...)) 

where c is a Number and args is of the form String, Int, String, Int, String, Int ... where String, Int come in pairs.

I’ve tried to at least enforcing that c is a number by doing

function Base.:+(a::MyType, (c::Number, args...)) 

and this does not compile

don’t think you can do that:

help?> Vararg
search: Vararg

  Vararg{T,N}

...

Vararg{T,N} corresponds to exactly N elements of type T.
1 Like

@jling is correct you cannot do this directly. And probably it would be best to refactor that interface a bit as it looks a bit strange.

That being said you could do:

function Base.:+(a::MyType, rest::Tuple{Number, Varargs{Any}})

or (if you changed the interface to pass tuples of String, Int)

function Base.:+(a::MyType, rest::Tuple{Number, Varargs{Tuple{String,Int}}})

Alternatively, just don’t constrain the arguments, if you don’t plan on using dispatch anyways. You might get away without ambiguities in this case because I think + has no method defined for Tuples, but I might be wrong and can’t check right now.

However, as said in the beginning: This complicated type signature probably wants to become a proper type. I.e. define a struct to hold your c::Int and Strings and Ints. That likely makes the code more legible and easier to understand.

3 Likes

The correct syntax is:

function Base.:+(a::MyType, (c, args...)::Tuple{Number,Vararg})
2 Likes

You might find the Pair type (constructed via "one" => 2 or Pair("one", 2) convenient for your pairs. You can constrain your (c, args...)::Tuple{Number, Vararg{Pair}} (or even get more specific with Pair{String,Int}) if you like, but as others have pointed out this is mostly useful if you plan to have the function behave differently with a different set of input types.

3 Likes