It's commonly used in order to allow for protocol extensions and generic placeholders constrained to protocols to call the initialiser on the given concrete type that conforms to the protocol. For example, consider RangeReplaceableCollection
's default implementation of init<S : Sequence>(_ elements: S)
:
extension RangeReplaceableCollection {
// ...
/// Creates a new instance of a collection containing the elements of a
/// sequence.
///
/// - Parameter elements: The sequence of elements for the new collection.
public init<S : Sequence>(_ elements: S) where S.Iterator.Element == Iterator.Element {
self.init()
append(contentsOf: elements)
}
// ...
}
Without init()
being defined as a protocol requirement of RangeReplaceableCollection
, there's no way for the extension to know that we can call init()
in order to create a new instance of the conforming type.
But it can also be used directly outside of generics and extensions – for example, it can be used to construct a new instance represented by a given existential metatype (the metatype of 'some concrete type that conforms to a protocol'):
protocol P {
init()
}
struct S : P {
init() {}
}
let s: P = S()
let s1 = type(of: s).init() // creates a new instance of S, statically typed as P.
In this example:
type(of: s)
returns the dynamic type of s
as P.Type
(an existential metatype), as s
is statically typed as P
. Remember that type(of:)
is a (T) -> T.Type
operation.
init()
constructs a new instance of the underlying concrete type, in this case S
.
The new instance is statically typed as P
(i.e boxed in an existential container).