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.
You're trying to enforce a 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.
The only thing you need is to add a requirement for an initializer to the protocol:
protocol P {
init()
}
struct A: P {
var x: Int
init() {
x = 10
}
}
func foo<T: P>(param param: T = T()) {
}
However, you will have another problem. The type of the passed parameter decides the type of the generic so you will have to specify the generic type somehow else.