Collection<Element>: Sequence public protocol RawRepresentable<RawValue> public protocol Identifiable<ID> public protocol InstantProtocol<Duration> public protocol MutableCollection<Element> public protocol RandomAccessCollection<Element> public protocol RangeExpression<Bound> public protocol RangeReplaceableCollection<Element> public protocol SIMD<Scalar> public protocol IteratorProtocol<Element> public protocol Sequence<Element> public protocol SetAlgebra<Element> public protocol Strideable<Stride> Introduced by SE-0358 “Primary Associated Types in the Standard Library” Collection
draw<T: Shape>(shape: T) { . . . } • Example: Generics (argument), Opaque Type (argument and return) • Abstract by using concrete type information (Type variable)
shape: any Shape = Rectangle() shape = Triangle() • Example: Existential Type (argument and return) • Abstract by erasing type information of value and use underlying (protocol) type
BigColoredRectangle: Shape { var color = UIColor.green var vertex = 4 } print(MemoryLayout.size(ofValue: Triangle())) print(MemoryLayout.size(ofValue: BigColoredRectangle())) let shape1: any Shape = Triangle() let shape2: any Shape = BigColoredRectangle() 8 16
var x: Int64 var y: Int64 var z: Int64 var w: Int64 Existential Container = Copy VeryBigRectangle() any Shape let shape: Reference x: Int y: Int z: Int w: Int
struct var x: Int64 var y: Int64 var z: Int64 var w: Int64 Existential Container = Copy VeryBigRectangle() any Shape let shape: x: Int y: Int z: Int w: Int
small struct var x: Int64 var y: Int64 func draw() Existential Container = Shape protocol func draw() Protocol Witness Table any Shape let shape: Triangle()
is selected on runtime Existential Container (Witness Table), Class (Virtual Table), Objective-C Runtime (Message Dispatch) … Method is selected on compile time struct, global function call, extension … Runtime Cost
of type (struct: 40Byte in 64bit CPU) • Existential Container allocates heap if the object exceeds its buffer • Existential Container method dispatch: Dynamic Dispatch
Existential type is initialized via Swift Intermediate Language(SIL) AST AST (Typed) SIL IR (LLVM) 📱 App • SIL shows many codes which is hidden in normal Swift code • Reference Count • Witness Table …
where Self : Shape> (Self) -> () -> () : @$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW } Protocol Function (‘Shape.draw’) Symbol of ‘Triangle.draw’ Protocol Witness Table of ‘Triangle’
} Protocol Function (‘Shape.draw’) Symbol of ‘Triangle.draw’ #Shape.draw : <Self where Self : Shape> (Self) -> () -> () @$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW Protocol Witness Table of ‘Triangle’
. . . %11 = witness_method $T . . . . . . } Try to check Witness Table of ‘shape’ from type variable ’T’ func draw<T: Shape>(shape: T) // draw is called inside of function Compile to SIL code
needed • Generics also uses Witness Table if Swift compiler doesn’t optimize code • Swift compiler’s optimizer generates “function with specialized argument“ Specialization of function argument with Generics
modules (or @_specialize) public func draw<T: Shape>(shape: T) draw(shape: Triangle()) @inlinable • Different module, complex type … etc • Function’s argument is not specialized in some cases Limitation of argument Specialization
and ‘some’ argument are also specialized if possible Specialization of ‘some’ and ‘any’ argument • Use appropriate ‘some’ and ‘any’ regardless of specialization any some YES YES NO (inline only) YES Same module Different module(inlinable) Specialization of some an any
• Github @ freddi-kit • Twitter @ _ _ _freddi_ _ _ Special Thanks @koher (Author of “Heart of Swift” https://heart-of-swift.github.io/) @kateinoigakukun (Swift Compiler specialist) Engineers and Interpreters in LINE Corp SwiftHeroes Team