Magic of hiding the type

Is my understanding correct that the “magic” of hiding the type happens in init ( we only disclose it on init time) here :

extension AnySequence: Sendable {}

extension AnySequence: Sequence {
public typealias Iterator = AnyIterator

/// Creates a new sequence that wraps and forwards operations to `base`.
@inlinable
public init<S: Sequence>(_ base: S)
where
S.Element == Element {
self._box = _SequenceBox(_base: base)
}
}
line 1302:

ExistentialCollection.swift

_SequenceBox is generic over S: Sequence. It is a subclass of _AnySequenceBox which is generic over some type Element. AnySequence is also generic over some type Element and contains a stored property of type _AnySequenceBox<Element>. So, when AnySequence is initialized, it creates an instance of _SequenceBox<S> and stores it in that stored property, which is where the type erasure effectively occurs.

There's no real magic at play here: it's just standard OOP inheritance and covariance.

2 Likes

The magic is that subclassing can change the generic signature and apply substitutions. That’s the non-trivial feature here; it’s not a given, because you could imagine a language where you can do this:

class Base<T> {}
class Derived<T>: Base<T> {}

But not this:

class Base {}
class Derived<T>: Base {}

Or this:

class Base<T> {}
class Derived: Base<Int> {}

For example, ponder how this works:

class Base {
  func f() {}
}
class Derived<T>: Base {
  override func f() {
    print(T.self)  // how do we know the T?
  }
}

let x: Base = Derived<Int>()
let y: Base = Derived<Bool>()
let z: Base = Bool.random() ? x : y
z.f()
4 Likes

Thanks. That was my question - is it happening during the initialisation.