JMI JMI - 4 months ago 19
Swift Question

Default parameter as generic type

I have protocol and his implementation written in Swift:

protocol P {
}

struct A: P {
}


Protocol is used as generic type for some function:

func foo<T: P>(param: T) {
}

func foo() {
foo(param: A())
}


Until now everything works properly. But I would like to set A() as a default parameter of given function:

func foo<T: P>(param: T = A()) {
}


Unfortunately with following error:


Default argument value of type 'A' cannot be converted to type 'T'.


Or

func foo<T: P>(param: T = A() as P) {
}


,

let a: P = A()
func foo<T: P>(param: T = a) {
}


Returns:


Default argument value of type 'P' cannot be converted to type 'T'


Or

func foo<T: P>(param: T = A() as T) {
}


Returns:


'A' is not convertible to 'T'; did you mean to use 'as!' to force downcast?


What I'm doing wrong? Where is the problem?

I do not want to use force cast like this:

func foo<T: P>(param: T = A() as! T) {
}


Thank you in advance.

Answer

You're trying to enforce as non-generic default argument in a generic function: you should probably think over what you're trying to achieve here.

For the sake of the discussion, you could include an attempted cast of A() to T in your function signature, but you'd need to change the argument type to optional to allow failed conversion (nil), e.g.

func foo<T: P>(param: T? = (A() as? T)) { }

A more sound alternative is including - in addition to your generic function - a concrete non-generic function for instances where T is A (concrete functions will take precedence over generic ones), in which case you can include the default argument of A() in the function signature of the concrete function. E.g.

protocol P { }
struct A: P { }
extension Int: P { }

func foo<T: P>(param: T) { print("called generic foo") }
func foo(param: A = A()) { print("called A specific foo") }

foo()    // called A specific foo (making use of default arg)
foo(A()) // called A specific foo
foo(1)   // called generic foo

Note that the non-generic foo is called even though A conforms to P (A could've made use of the generic foo): there's no conflict here as the concrete function takes precedence.


If you, on the other hand, just want your generic function to allow calling without the single argument (i.e., making use of a default argument), you can include a blueprint of a simple initializer in P, allowing you to initialize an instance of the generic type as default argument; see @Sulthan:s answer.

Comments