Variadic functions as subtypes

Please excuse me if this does not make sense at all, but I got to thinking about using a variadic function as subtypes.

Example:

func variadic(items: String...) {
    ...
}
func consumer(_ a: (String, String) -> Void) {
    a("1", "2")
}
consumer(variadic)  // Compiler error

Since it is fine to call variadic directly with two Strings, it would appear that a variadic function is somehow a subtype of a function with similar, but fixed parameters.

So in that sense, would it make sense to make variadic functions into actual subtypes of all 'compatible' functions?

I guess a similar question could be asked about default parameters: Would it make sense to treat a function with default parameters as a subtype of a function where any of the default parameters are skipped?

4 Likes

Yes, String... is indeed a supertype of (String,String) and by the law of contravariance for function parameters, an entity of type String...->Void should be substitutable to an entity of type (String,String)->Void.

2 Likes

Yes, but because both functions share the same type which means they are a subtype of each other. The reason is that default values don't really belong to function signatures, they are merely syntactic sugar for the compiler to autofill the missing fields.
You should indeed assign safely a function with default params to a function expecting all params and vice versa.

Well, String... is not a type in Swift's type system. Variadics are a property of function parameters; the parameter type "really" has an array type and the variadic parameter flag is syntax sugar for the compiler to wrap the arguments in an array literal at the call site. Today the subtyping rule for function types requires that both function types have the same number of parameters for one to be a subtype of the other.

5 Likes