I’m studying generics and "some" keyword in Swift and for testing I have this situation:
protocol Vehicle {
var name: String { get }
}
struct Car: Vehicle {
let name = "car"
}
struct Bus: Vehicle {
let name = "bus"
}
Then I tried to create some functions for testing various scenario:
func wash<T : Vehicle>(_ vehicle: T, x : Int) -> T{
if(x < 10){
return Car() as! T
}
return Bus() as! T
}
This function is ok and I know why.
If I change it using "some":
func wash<T : Vehicle>(_ vehicle: T, x : Int) -> some Vehicle{
if(x < 10){
return Car()
}
return Bus()
}
I get this error:
Function declares an opaque return type 'some Vehicle', but the return statements in its body do not have matching underlying types
My question is: both functions I wrote that I want to get Vehicle object, why the second is wrong? (I thought maybe the "some" keyword wants to know the object type to compile time and because there is "if" in the body, it can determinate only runtime, but I don’t know).
For resolve the second function problem I tried to use "any", but I don’t know because I don’t get the error:
func wash<T : Vehicle>(_ vehicle: T, x : Int) -> any Vehicle{
if(y < 10){
return Car()
}
return Bus()
}
Can you explain this difference?
2
Answers
I think the thing you might consider is to change your generic func into a usable one for your case. Why not use your protocol in the first place ?
I mean something like this kind :
then about your question about
some
andany
keywords, your example seems to refer to this article : https://swiftsenpai.com/swift/understanding-some-and-any/you should read again carefully because all the explanations are there.
This function is absolutely not ok, and will crash in general. This function says "the caller may request any specific Vehicle type, and this function will return it." That’s not what happens at all. It only compiles because you promise (using
as!
) that it will work out at runtime, and if it doesn’t, then you’ve asked for the program to crash.Your second function is the correct one, though today it would be better written:
This says that the caller may pass a specific ("some") Vehicle (i.e. Car, Bus, or something else), and that this function will return a general ("any") Vehicle existential. An "existential" is a wrapper around a specific (concrete) Vehicle that only exposes the interface of the protocol. So the various links in the comments and other answers for much more on the difference between
some
andany
.