I have a question regarding using the some
vs any
keyword in Swift. As you may see in the below code that the init
method in CarVersion1
uses some
while CarVersion2
use any
. My question is which version is better and why?
protocol Engine { var typeName: String { get } }
final class ElectricEngine: Engine { var typeName: String { "Electric Engine" } }
final class PetrolEngine: Engine { var typeName: String { "Petrol Engine" } }
final class DieselEngine: Engine { var typeName: String { "Diesel Engine" } }
final class CarVersion1 {
private var engine: any Engine
init(engine: any Engine) { self.engine = engine }
func printEngineType() { print(engine.typeName) }
}
final class CarVersion2 {
private var engine: any Engine
init(engine: some Engine) { self.engine = engine }
func printEngineType() { print(engine.typeName) }
}
let car1 = CarVersion1(engine: ElectricEngine())
car1.printEngineType()
let car2 = CarVersion2(engine: ElectricEngine())
car2.printEngineType()
2
Answers
The following are almost identical:
Because
some
is resolving the underlying concrete type at the compile time.any
on the other hand, acts very similar but unlikesome
and generic, it will NOT expose the actual concrete type until the runtime.Usually, you should prefer to use
some
(compile-time) overany
(run-time) anywhere you can for the sake of performance, safety and reliability.In your specific case, it doesn’t particularly matter, since you immediately turn around and store it in an
any Engine
. Theany
existential box has to be constructed in either case, and so you don’t get much benefit from usingsome
in theinit
. (It’s possibly a little worse, but I would expect it generally just doesn’t matter.)Where you would get some benefits is if you made Car generic over its Engine:
This way there is no existential box required. More code can be inlined. More dispatch is static rather than dynamic. When reasonable, this is the preferred approach. The only problem is that because CarVersion3 is generic, you cannot create an Array of multiple cars with different engines. And if you need to store this in a property, it may force the containing type to also be be generic. Generics spread. That’s the trade-off.
I realize in CarVersion3 there is no
some
. So, to get to your underlying question,some
is fairly unusual in aninit
parameter. You cannot have a stored property of asome
type, so there usually isn’t a reason to pass one toinit
. The generic type is expressed on the container, not on theinit
.