I’m pretty new in the iOS development world and I’m trying to understand protocols in Swift. Here’s my code:
protocol Animal {
func printFood()
}
struct Rabbit: Animal {
func printFood() {
print("carrot")
}
}
struct Sheep: Animal {
func printFood() {
print("grass")
}
}
I have this very simple protocol with these two structs conforming to it. I wrote these two functions:
func printAnimalFood<A: Animal>(_ animal: A) {
animal.printFood()
}
func printAnimalFood(_ animal: Animal) {
animal.printFood()
}
Is this the same way to write the same thing? Or not? In many examples I see a lot of functions written in the first way but I don’t understand why since I can use the second way and obtain the same result. Why should I introduce a generic type parameter since I can directly use the protocol as parameter? Is there any subtle difference? Are there some situations in which I should use the first "syntax" over the second one and vice versa?
I tried to execute both the functions and, as expected, the printed result is the same, with no difference.
2
Answers
Protocols as Parameters:
When you define a function or method that takes a protocol as a parameter, it means that any value passed to that parameter must conform to the specified protocol. This allows you to write more flexible and reusable code.
Protocols as Generic Types:
When you use a protocol as a generic type, it means that the generic type placeholder can be any type that conforms to the specified protocol. This allows you to create more generic and flexible code that can work with different types that share common behaviors.
In the code that you wrote there is no noticeable difference from usage point of view. The two will probably be complied differently though.
You in most cases don’t need to restrict it with generic. But doing so can allow you to do some additional things.
For instance if you wish to compare two animals you can not do this
mostly because you can not compare your sheep to your rabbits. So you need to restrict it with generic to ensure that both animas are actually of the same type:
Also when using return type things can get pretty dicey. Imagine you want to do something like this:
if you define a feed method without a generic you have no relation between input animal and an output animal. So the method itself does not restrict you from returning a
Rabbit
instead of a sheep. So examine the two methods:The first one will ensure that if you are feeding a
Rabbit
you will get back aRabbit
, and if you are feeding aSheep
you are getting back aSheep
. The second method will have no such restrictions and the returned value can be any type ofAnimal
, regardless of the input.But these are just basics. Most of the problems where you need a generic restriction actually comes with introducing associated value to a protocol. You may find some interesting cases down that road. But as a beginner I suggest that you always try to solve it without a generic. If you get some strange errors related to it then maybe try using
some Animal
. And if that fails try with generic restriction.And for better understanding of errors try this (absurd) method.
You should first get two errors where first will tell you to add
any
beforeComparable
. The second then becomes tricky saying "Binary operator ‘==’ cannot be applied to two ‘any Comparable’ operands" which basically means "I can’t compare apples to oranges". So you need to usesome
instead ofany
.