Swift provides three primary collection types —arrays, sets, and dictionaries— implemented as generic types, which means they can store any type of value as long as it conforms to certain protocols.
Heterogeneous and homogeneous are terms that describe the types of values that a collection can store. A heterogeneous collection can store values of different types, as long as they conform to a common protocol. A homogeneous collection can only store values of the same type.
Swift does support heterogeneous collections, which are collections that can hold values of different types. However, there are some limitations and trade-offs to consider when using them.
any Animal
, which can hold any type that conforms to the Animal
protocol. For example:let animals: [any Animal] = [Dog(name: "Spot"), Bird(name: "Tweety"), Fish(name: "Nemo")]
However, existential types have some drawbacks, such as being less efficient, less type-safe, and less expressive than generic type constraints.
AnyHashable
, which can hold any type that conforms to the Hashable
protocol. For example:let values: [AnyHashable] = [1, "hello", true]
However, type-erasing wrappers also have some drawbacks, such as losing some of the original type information and functionality, and requiring explicit casting to access the underlying value.
enum Value {
case int(Int)
case string(String)
case bool(Bool)
}
let values: [Value] = [.int(1), .string("hello"), .bool(true)]
However, enums with associated values also have some drawbacks, such as being more verbose and requiring pattern matching to access the associated value.
Therefore, depending on your use case and requirements, you may choose one of these ways or a combination of them to create heterogeneous collections in Swift. Alternatively, you may consider using homogeneous collections with generic type constraints if possible, as they offer more advantages in terms of performance, type safety, and expressiveness.