I found the following example on the web about using generics together with protocols, however I don\'t understand why do we need generics at all, when all we need is to use
They express different things. With
func check(object: inout Healthy) {
The object argument can be any Healthy conforming instance. Therefore, you could do this:
protocol Healthy {}
struct Foo : Healthy {}
struct Bar : Healthy {}
func check(object: inout Healthy) {
object = Bar()
}
var h: Healthy = Foo()
check(object: &h)
print(h) // Bar()
We called check(object:) and passed h (which holds a Foo instance) as the inout argument, but ended up with h holding a Bar instance.
You'll note that this means we cannot simply call check(object:) with a concrete-typed inout argument. The following doesn't compile:
var h = Foo()
// compiler error: Cannot pass immutable value as inout argument:
// implicit conversion from 'Foo' to 'Healthy' requires a temporary
check(object: &h)
Because check(object:) could assign an arbitrary Healthy conforming instance to the object argument, which is not assignable to a Foo variable.
However, with
func check(object: inout T) {
The object argument is a single specific concrete type that conforms to Healthy (and this type is satisfied at the call-site). You cannot just assign an arbitrary Healthy conforming instance to it, as it might not be compatible with the variable type being passed as the inout argument.
This therefore now allows you to call it with a concrete-typed inout argument. We can now say:
protocol Healthy {
var alive: Bool { get set }
}
struct Foo : Healthy {
var alive: Bool
}
struct Bar : Healthy {
var alive: Bool
}
func check(object: inout T) {
object.alive = false
// illegal
// object = Bar()
}
var h = Foo(alive: true)
check(object: &h)
(note h is able to be typed as Foo)
So in most cases, you'll likely want to make the method generic rather than having a protocol-typed inout parameter, as you'll likely want to be dealing with concrete types.