freddi(Yuki Aki)
May 04, 2023
1.2k

# Deep Dive into "any" and "some"

At SwiftHeroes 2023

May 04, 2023

## Transcript

1. ### Deep Dive into “any” and “some” Yuki ‘freddi’ Aki, LINE

SwiftHeroes 2023 Secrets from deep side of Swift
2. ### ‘any’ and ‘some’ evolution ‘any’ Mechanism with Existential Container Optimization

of ‘any’ and ‘some’
3. ### ‘any’ and ‘some’ evolution Optimization of ‘any’ and ‘some’ ‘any’

Mechanism with Existential Container
4. ### ‘any’ and ‘some’ evolution ‘any’ Mechanism with Existential Container Optimization

of ‘any’ and ‘some’
5. ### ‘any’ and ‘some’ evolution ‘any’ Mechanism with Existential Container Optimization

of ‘any’ and ‘some’
6. ### ‘any’ and ‘some’ evolution ‘any’ Mechanism with Existential Container Optimization

of ‘any’ and ‘some’

Type
12. ### protocol Shape { . . . } struct Rectangle: Shape

{} struct Triangle: Shape {} Example of Existential Type
13. ### protocol Shape { . . . } = /* make

assignable any object conform to Shape */ Example of Existential Type var shape
14. ### protocol Shape { . . . } : Shape =

Rectangle() Example of Existential Type var shape
15. ### protocol Shape { . . . } var shape: Shape

= Rectangle() shape = Triangle() Example of Existential Type
16. ### protocol Shape { . . . } var shape: shape

= Triangle() ‘Shape’ is Existential Type Example of Existential Type Shape = Rectangle() Shape
17. ### protocol Shape { . . . } SE-0335 Introduce existential

‘any’ ‘any Shape’ is Existential Type // SE-0355, any is forced from Swift 6 var shape: shape = Triangle() Shape = Rectangle() any any
18. ### var shape: shape = Triangle() Existential Type’s cost Existential Container

any Shape Shape = Rectangle() any
19. ### Existential Type’s cost Existential Container any Shape Read value Call

Functions Performance Cost var shape: shape = Triangle() Shape = Rectangle() any

21. ### Existential Type? Class? Structure? // Does Shape have existential container’s

cost? var shape: Shape
22. ### any Existential Type? Class? Structure? // It is more clear

that ‘Shape’ is existential type var shape: Shape

A }
24. ### let x: SE-0309 Unlock existentials for all protocols protocol P

{ associatedtype A } ~ Swift 5.6 P = /* ... */
25. ### SE-0309 Unlock existentials for all protocols protocol P { associatedtype

A } Swift 5.7 ~ let x: P = /* ... */ any

27. ### protocol P<A> { associatedtype A } P<A> Introduced by SE-0346

“Lightweight same-type requirements for primary associated types”
28. ### public protocol Clock<Duration>: Sendable public protocol BidirectionalCollection<Element>: Collection public protocol

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
29. ### func <C: >(_ collection: C) where C.Element == Int {

. . . } Collection apply

31. ### func apply(_ collection: any Collection<Int>) { . . . }

Introduced by SE-0353 “Constrained Existential Types”
32. ### protocol P<A> { associatedtype A } func method(_ p: any

P<Int> ) { . . . } extension P<Int> { . . . } P<A> P<Int> Don’t need to write “P where A == Int” P<Int>
33. ### protocol P<A> { associatedtype A } func method(_ p: any

P<Int> ) { . . . } extension P<Int> { . . . } let p: any P<Int> P<A> P<Int> Don’t need to prepare hand-made type erasure P<Int>

36. ### Existential Type’s cost func method(_ p: . . . }

‘any’ uses Existential Container P<Int>) { any
37. ### Existential Type’s cost Opaque Type (‘some’) doesn’t require Existential Container

(SE-341 Opaque Parameter Declarations) some func method(_ p: . . . } P<Int>) {

T) { . . . }
39. ### Generics and Opaque Type in argument • Generics doesn’t use

Existential Container because “Keeps type information" func method<T: P>(_ p: T) { . . . }
40. ### Generics and Opaque Type in argument func method(_ p: some

P) { . . . } ← • Generics doesn’t use Existential Container because “Keeps type information" • Opaque Type argument is syntax sugar of Generics func method<T: P>(_ p: T) { . . . } swiftc

. . . }

43. ### Type-level abstraction protocol Shape { . . . } func

draw<T: Shape>(shape: T) { . . . } • Example: Generics (argument), Opaque Type (argument and return) • Abstract by using concrete type information (Type variable)
44. ### Value-level abstraction protocol Shape { . . . } var

shape: any Shape = Rectangle() shape = Triangle() • Example: Existential Type (argument and return) • Abstract by erasing type information of value and use underlying (protocol) type
45. ### Return Argument Existential type Type-level abstraction Value-level abstraction Generics ~

Swift 4 Protocol abstraction
46. ### Return Argument Existential type Type-level abstraction Value-level abstraction Generics Existential

type ~ Swift 4 Protocol abstraction

49. ### Cannot convert return expression of type ‘P‘ to return type

‘PImpl' <PType: P> PType func method PImpl() } () -> {

} () -> {

-> {
53. ### let p = method() p.pImplFunc() No room for the developer

to change the return type of the API Too opened implementation Detail PImpl func method PImpl() } () -> {

55. ### -> <PType: P> PType “Reverse Generics” (not implemented) func method

PImpl() } () () -> {
56. ### var p = method() “Reverse Generics” (not implemented) Treat type

as “some type conforms P” -> <PType: P> PType func method PImpl() } () -> {
57. ### var p = method() Introduced by SE-0244 “Opaque Result Type”

some P func method PImpl() } some () -> {
58. ### Return Argument Existential type Existential type Type-level abstraction Value-level abstraction

Generics Opaque Type (5.7) Opaque Type (5.1) Swift 5 (5.1 and 5.7) ~ Protocol abstraction
59. ### ‘any’ and ‘some’ evolution ‘any’ Mechanism with Existential Container Optimization

of ‘any’ and ‘some’
60. ### ‘any’ and ‘some’ evolution ‘any’ Mechanism with Existential Container Optimization

of ‘any’ and ‘some’
61. ### How Existential Type works? var shape: any Shape = Rectangle()

shape = Triangle()
62. ### How Existential Type works? var shape: any Shape = Rectangle()

shape = Triangle() Existential Container any Shape
63. ### How Existential Type works? var shape: any Shape = Rectangle()

shape = Triangle() Existential Container any Shape
64. ### How Existential Type works? var shape: any Shape = Rectangle()

shape = Triangle() Existential Container any Shape
65. ### struct Triangle: Shape { var vertex = 3 } struct

BigColoredRectangle: Shape { var color = UIColor.green var vertex = 4 }
66. ### struct Triangle: Shape { var vertex = 3 } struct

BigColoredRectangle: Shape { var color = UIColor.green var vertex = 4 } print(MemoryLayout.size(ofValue: Triangle())) print(MemoryLayout.size(ofValue: BigColoredRectangle())) 8 16
67. ### struct Triangle: Shape { var vertex = 3 } struct

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
68. ### struct Triangle: Shape { var vertex = 3 } struct

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() print(MemoryLayout.size(ofValue: shape1)) print(MemoryLayout.size(ofValue: shape2)) 8 16 40 40

48
70. ### struct VeryBigRectangle: Shape { . . . } print(MemoryLayout.size(ofValue: VeryBigRectangle()))

let shape: any Shape = VeryBigRectangle() print(MemoryLayout.size(ofValue: shape)) 48 40

72. ### any Shape Object in Existential Container (struct) small struct var

x: Int64 var y: Int64 Existential Container let shape: = Triangle()
73. ### Object in Existential Container (struct) small struct var x: Int64

var y: Int64 Existential Container = 40byte any Shape let shape: Triangle()
74. ### Object in Existential Container (struct) Buffer(64bit) Buffer(64bit) Buffer(64bit) small struct

var x: Int64 var y: Int64 Existential Container = any Shape let shape: Triangle()
75. ### Object in Existential Container (struct) x: Int64 y: Int64 Buffer(64bit)

small struct var x: Int64 var y: Int64 Existential Container = any Shape let shape: Triangle()
76. ### VeryBigRectangle() Object in Existential Container (struct) Buffer(64bit) Buffer(64bit) Buffer(64bit) large

struct var x: Int64 var y: Int64 var z: Int64 var w: Int64 Existential Container = any Shape let shape:
77. ### Object in Existential Container (struct) Buffer(64bit) Buffer(64bit) Heap large struct

var x: Int64 var y: Int64 var z: Int64 var w: Int64 Existential Container = VeryBigRectangle() any Shape let shape: Reference
78. ### Object in Existential Container (struct) Buffer(64bit) Buffer(64bit) Heap large struct

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
79. ### Object in Existential Container (struct) Reference Buffer(64bit) Buffer(64bit) Heap large

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
80. ### struct VeryBigRectangle: Shape { . . . } print(MemoryLayout.size(ofValue: VeryBigRectangle()))

let shape: any Shape = VeryBigRectangle() print(MemoryLayout.size(ofValue: shape)) 40 (without Heap area size)

82. ### Method Dispatch of Existential Container Buffer(64bit) Buffer(64bit) Buffer(64bit) Existential Container

Protocol Witness Table

84. ### Witness Table Value Witness Table Protocol Witness Table Information of

Type Allocation, Deinitialization, size, stride …
85. ### Witness Table Value Witness Table Protocol Witness Table Information for

Method Dispatch (Method Table) Used when selecting the function of protocol Information of Type Allocation, Deinitialization, size, stride …
86. ### Method Dispatch of Existential Container x: Int64 y: Int64 Buffer(64bit)

small struct var x: Int64 var y: Int64 Existential Container = Protocol Witness Table any Shape let shape: Triangle()
87. ### Method Dispatch of Existential Container x: Int64 y: Int64 Buffer(64bit)

small struct var x: Int64 var y: Int64 func draw() Existential Container = Shape protocol func draw() Protocol Witness Table any Shape let shape: Triangle()
88. ### x: Int64 y: Int64 Buffer(64bit) small struct var x: Int64

var y: Int64 func draw() Existential Container = Shape protocol func draw() Name Which func needs call? draw() Triangle.draw() Protocol Witness Table Method Dispatch of Existential Container any Shape let shape: Triangle() Triangle’s Protocol Witness Table
89. ### x: Int64 y: Int64 Buffer(64bit) small struct var x: Int64

var y: Int64 func draw() Existential Container = Shape protocol func draw() Name Which func needs call? draw() Triangle.draw() Protocol Witness Table Method Dispatch of Existential Container any Shape let : Triangle() Triangle’s Protocol Witness Table shape
90. ### x: Int64 y: Int64 Buffer(64bit) Existential Container .draw() Protocol Witness

Table Method Dispatch of Existential Container shape
91. ### x: Int64 y: Int64 Buffer(64bit) Existential Container Name Which func

needs call? draw() Triangle.draw() combine() Triangle.combine() … … Protocol Witness Table Method Dispatch of Existential Container shape .draw()
92. ### x: Int64 y: Int64 Buffer(64bit) Existential Container Protocol Witness Table

Method Dispatch of Existential Container shape .draw() Name Which func needs call? draw() Triangle.draw() combine() Triangle.combine() … …

94. ### Method Dispatch of Existential Type Dynamic Dispatch Static Dispatch Method

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

Table
96. ### Existential Container (struct) Buffer(64bit) Buffer(64bit) Buffer(64bit) Existential Container Metadata Protocol

Witness Table Record of type information with Value Witness Table
97. ### Existential Container (struct) Buffer(64bit) Buffer(64bit) Buffer(64bit) Existential Container Metadata Protocol

Witness Table 64bit + 64bit + 64bit = 192bit (24byte) 64bit (8byte) 8byte 40byte

99. ### Summary: Existential Container • Existential Container size is fixed regardless

of type (struct: 40Byte in 64bit CPU)
100. ### Summary: Existential Container • Existential Container allocates heap if the

object exceeds its buffer • Existential Container size is fixed regardless of type (struct: 40Byte in 64bit CPU)
101. ### Summary: Existential Container • Existential Container size is fixed regardless

of type (struct: 40Byte in 64bit CPU) • Existential Container allocates heap if the object exceeds its buffer • Existential Container method dispatch: Dynamic Dispatch

103. ### How Existential Container actually works? • We can see how

Existential type is initialized via Swift Intermediate Language(SIL)
104. ### How Existential Container actually works? • We can see how

Existential type is initialized via Swift Intermediate Language(SIL) AST AST (Typed) SIL IR (LLVM) 📱 App
105. ### How Existential Container actually works? • We can see how

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 …
106. ### protocol Shape { func draw() } struct Triangle: Shape {

func draw() {} } let shape: any Shape = Triangle() shape.draw()
107. ### protocol Shape { func draw() } struct Triangle: Shape {

func draw() {} } let shape: any Shape = Triangle() shape.draw() \$ swiftc heroes.swift -emit-sil -o heroes.sil
108. ### sil_stage canonical import Builtin import Swift import SwiftShims protocol Shape

{ func draw() } struct Triangle : Shape { func draw() init() } @_hasStorage @_hasInitialValue let shape: Shape { get } // shape sil_global hidden [let] @\$s6heroes5shapeAA5Shape_pvp : \$Shape // main sil @main : \$@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : \$Int32, %1 : \$UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp : \$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to \$*@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape // users: %9, %9, %8 %8 = witness_method \$@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$*@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@in_guaranteed τ_0_0) -> () // type-defs: %7; user: %9 %9 = apply %8<@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@in_guaranteed τ_0_0) -> () // type-defs: %7 %10 = integer_literal \$Builtin.Int32, 0 // user: %11 %11 = struct \$Int32 (%10 : \$Builtin.Int32) // user: %12 return %11 : \$Int32 // id: %12 } // end sil function 'main' // Triangle.draw() sil hidden @\$s6heroes8TriangleV4drawyyF : \$@convention(method) (Triangle) -> () { // %0 "self" // user: %1 bb0(%0 : \$Triangle): debug_value %0 : \$Triangle, let, name "self", argno 1, implicit // id: %1 %2 = tuple () // user: %3 return %2 : \$() // id: %3 } // end sil function '\$s6heroes8TriangleV4drawyyF' // Triangle.init() sil hidden @\$s6heroes8TriangleVACycfC : \$@convention(method) (@thin Triangle.Type) -> Triangle { // %0 "\$metatype" bb0(%0 : \$@thin Triangle.Type): %1 = struct \$Triangle () // user: %2 return %1 : \$Triangle // id: %2 } // end sil function '\$s6heroes8TriangleVACycfC' // protocol witness for Shape.draw() in conformance Triangle sil private [transparent] [thunk] @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW : \$@convention(witness_method: Shape) (@in_guaranteed Triangle) -> () { // %0 // user: %1 bb0(%0 : \$*Triangle): %1 = load %0 : \$*Triangle // user: %3 // function_ref Triangle.draw() %2 = function_ref @\$s6heroes8TriangleV4drawyyF : \$@convention(method) (Triangle) -> () // user: %3 %3 = apply %2(%1) : \$@convention(method) (Triangle) -> () %4 = tuple () // user: %5 return %4 : \$() // id: %5 } // end sil function ‘\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW’ // Mappings from '#fileID' to '#filePath': // 'heroes/heroes.swift' => 'heroes.swift' sil_witness_table hidden Triangle: Shape module heroes { method #Shape.draw: <Self where Self : Shape> (Self) -> () -> () : @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW // protocol witness for Shape.draw() in conformance Triangle }
109. ### sil_witness_table hidden Triangle: Shape module heroes { method #Shape.draw: <Self

where Self : Shape> (Self) -> () -> () : @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW } Protocol Witness Table of ‘Triangle’
110. ### sil_witness_table hidden Triangle: Shape module heroes { method #Shape.draw: <Self

where Self : Shape> (Self) -> () -> () : @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW } Protocol Function (‘Shape.draw’) Protocol Witness Table of ‘Triangle’
111. ### sil_witness_table hidden Triangle: Shape module heroes { method #Shape.draw: <Self

where Self : Shape> (Self) -> () -> () : @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW } Protocol Function (‘Shape.draw’) Symbol of ‘Triangle.draw’ Protocol Witness Table of ‘Triangle’
112. ### sil_stage canonical import Builtin import Swift import SwiftShims protocol Shape

{ func draw() } struct Triangle : Shape { func draw() init() } @_hasStorage @_hasInitialValue let shape: Shape { get } // shape sil_global hidden [let] @\$s6heroes5shapeAA5Shape_pvp : \$Shape // main sil @main : \$@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : \$Int32, %1 : \$UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): %10 = integer_literal \$Builtin.Int32, 0 // user: %11 %11 = struct \$Int32 (%10 : \$Builtin.Int32) // user: %12 return %11 : \$Int32 // id: %12 } // end sil function 'main' // Triangle.draw() sil hidden @\$s6heroes8TriangleV4drawyyF : \$@convention(method) (Triangle) -> () { // %0 "self" // user: %1 bb0(%0 : \$Triangle): debug_value %0 : \$Triangle, let, name "self", argno 1, implicit // id: %1 %2 = tuple () // user: %3 return %2 : \$() // id: %3 } // end sil function '\$s6heroes8TriangleV4drawyyF' // Triangle.init() sil hidden @\$s6heroes8TriangleVACycfC : \$@convention(method) (@thin Triangle.Type) -> Triangle { // %0 "\$metatype" bb0(%0 : \$@thin Triangle.Type): %1 = struct \$Triangle () // user: %2 return %1 : \$Triangle // id: %2 } // end sil function '\$s6heroes8TriangleVACycfC' // protocol witness for Shape.draw() in conformance Triangle sil private [transparent] [thunk] @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW : \$@convention(witness_method: Shape) (@in_guaranteed Triangle) -> () { // %0 // user: %1 bb0(%0 : \$*Triangle): %1 = load %0 : \$*Triangle // user: %3 // function_ref Triangle.draw() %2 = function_ref @\$s6heroes8TriangleV4drawyyF : \$@convention(method) (Triangle) -> () // user: %3 %3 = apply %2(%1) : \$@convention(method) (Triangle) -> () %4 = tuple () // user: %5 return %4 : \$() // id: %5 } // end sil function ‘\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW’ // Mappings from '#fileID' to '#filePath': // 'heroes/heroes.swift' => 'heroes.swift' sil_witness_table hidden Triangle: Shape module heroes { method #Shape.draw: <Self where Self : Shape> (Self) -> () -> () : @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW // protocol witness for Shape.draw() in conformance Triangle } alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp : \$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to \$*@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape // users: %9, %9, %8 %8 = witness_method \$@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$*@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@in_guaranteed τ_0_0) -> () // type-defs: %7; user %9 = apply %8<@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@in_guaranteed τ_0_0) -> () // type-defs: %7
113. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to \$*@opened("CA01F70C-D958-11ED-8F40- %8 = witness_method \$@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape, #Shape.draw : <Self %9 = apply %8<@opened("CA01F70C-D958-11ED-8F40-9E59F6EF2BA0") Shape>(%7) : \$@convention(witness let shape: any Shape = Triangle() shape.draw() %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@
114. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw()
115. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw() Allocating memory area for shape
116. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw() Call ‘Triangle’s initializer to create object Allocating memory area for shape
117. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw() Create Existential Container and assign ‘Triangle’ object Call ‘Triangle’s initializer to create object Allocating memory area for shape
118. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw()
119. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw()
120. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw() Load Existential Container
121. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw() Load Existential Container Get function symbol of Shape.draw from Protocol Witness Table in Existential Container
122. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, #Shape.draw : <Self where Self : Shape> (Self) -> () -> (), %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw() #Shape.draw : <Self where Self : Shape> (Self) -> () -> () Load Existential Container Get function symbol of Shape.draw from Protocol Witness Table in Existential Container
123. ### sil_witness_table hidden Triangle: Shape module heroes { method : @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW

} Protocol Function (‘Shape.draw’) Symbol of ‘Triangle.draw’ #Shape.draw : <Self where Self : Shape> (Self) -> () -> () @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW Protocol Witness Table of ‘Triangle’
124. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, , %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw() #Shape.draw : <Self where Self : Shape> (Self) -> () -> () Obtained: @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW Load Existential Container Get function symbol of Shape.draw from Protocol Witness Table in Existential Container
125. ### alloc_global @\$s6heroes5shapeAA5Shape_pvp // id: %2 %3 = global_addr @\$s6heroes5shapeAA5Shape_pvp :

\$*Shape // users: %7, %5 %4 = struct \$Triangle () // user: %6 %5 = init_existential_addr %3 : \$*Shape, \$Triangle // user: %6 store %4 to %5 : \$*Triangle // id: %6 %7 = open_existential_addr immutable_access %3 : \$*Shape to … Shape // users: %9, %9, %8 %8 = witness_method … Shape, , %7 : \$ %9 = apply %8<… Shape>(%7) : \$@convention(witness_method: Shape) <τ_0_0 where τ_0_0 : Shape> (@ let shape: any Shape = Triangle() shape.draw() #Shape.draw : <Self where Self : Shape> (Self) -> () -> () The function is called with selected information (Dynamic Dispatch) Load Existential Container Get function symbol of Shape.draw from Protocol Witness Table in Existential Container Obtained: @\$s6heroes8TriangleVAA5ShapeA2aDP4drawyyFTW

127. ### %8 = load %3 : \$*Triangle // user: %10 //

function_ref Triangle.draw() %9 = function_ref @\$s6heroes8TriangleV4drawyyF : \$@convention(method) (Triangle) -> () // user: %10 = apply %9(%8) : \$@convention(method) (Triangle) -> () let shape = Triangle() shape.draw()
128. ### %8 = load %3 : \$*Triangle // user: %10 //

function_ref Triangle.draw() %9 = function_ref @\$s6heroes8TriangleV4drawyyF : \$@convention(method) (Triangle) -> () // user: %10 = apply %9(%8) : \$@convention(method) (Triangle) -> () Function symbol (\$s6heroes8TriangleV4drawyyF) is selected (Static Dispatch) let shape = Triangle() shape.draw()

130. ### let shape: some Shape = Triangle() shape.draw() ??? Please try:\$

swiftc heroes.swift -emit-sil -o heroes.sil
131. ### ‘any’ and ‘some’ evolution ‘any’ Mechanism with Existential Container Optimization

of ‘any’ and ‘some’
132. ### ‘any’ and ‘some’ evolution ‘any’ Mechanism with Existential Container Optimization

of ‘any’ and ‘some’

function
134. ### // draw<A>(shape:) sil hidden @\$s6heroes4draw5shapeyx_tAA5ShapeRzlF : . . . {

. . . %11 = witness_method \$T . . .   . . . } func draw<T: Shape>(shape: T) // draw is called inside of function Compile to SIL code
135. ### // draw<A>(shape:) sil hidden @\$s6heroes4draw5shapeyx_tAA5ShapeRzlF : . . . {

. . . %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
136. ### • Generics also uses Witness Table if Swift compiler doesn’t

optimize function code Specialization of function argument with Generics
137. ### • Generics also uses Witness Table if Swift compiler doesn’t

optimize function code • Optimizer in Swift compiler generates “function with specialized argument“ Specialization of function argument with Generics

139. ### func draw<T: Shape>(shape: T) draw(shape: Triangle()) Compile code with optimization

(‘-O’ flag) // specialized draw<A>(shape:) sil hidden @\$s6heroes4draw5shapeyx_tAA5ShapeRzlFAA8TriangleC_Tg5
140. ### func draw<T: Shape>(shape: T) draw(shape: Triangle()) Compile code with optimization

(‘-O’ flag) // specialized draw<A>(shape:) sil hidden @\$s6heroes4draw5shapeyx_tAA5ShapeRzlFAA8TriangleC_Tg5 ‘draw(shape: Triangle)’
141. ### • Specialized function has concrete type information, and witness_table isn’t

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
142. ### public func draw<T: Shape>(shape: T) draw(shape: Triangle()) Module A Module

B class OriginalShape: ModuleA.Shape draw(shape: OriginalShape())
143. ### public func draw<T: Shape>(shape: T) draw(shape: Triangle()) Module A Module

B class OriginalShape: ModuleA.Shape draw(shape: OriginalShape()) Specialized
144. ### public func draw<T: Shape>(shape: T) draw(shape: Triangle()) Module A Module

B class OriginalShape: ModuleA.Shape draw(shape: OriginalShape()) Specialized Not-Specialized
145. ### • Function’s argument is not specialized in some cases Limitation

of argument Specialization
146. ### • Different module, complex type … etc • Function’s argument

is not specialized in some cases Limitation of argument Specialization
147. ### • Use ‘@inlinable’ attribute to make specializable in outside of

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

149. ### Specialization of ‘any’ and ‘some’ argument • ‘some’ argument still

uses Witness Table as default
150. ### • ‘some’ argument still uses Witness Table as default •

‘any’ and ‘some’ argument are also specialized if possible Specialization of ‘any’ and ‘some’ argument

152. ### // specialized draw(shape:) sil hidden @\$s6heroes4draw5shapeyAA5Shape_p_..._nAA8TriangleC_Tg5 func draw(shape: any Shape)

draw(shape: Triangle()) Compile code with optimization (‘-O’ flag) ‘draw(shape: Triangle)’
153. ### • ‘some’ still uses Witness Table as default • ‘any’

and ‘some’ argument are also specialized if possible Specialization of ‘some’ and ‘any’ argument
154. ### • ‘some’ still uses Witness Table as default • ‘any’

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

156. ### Summary: Optimization • Existential Type, Opaque Type and Generics are

“specialized” by compiler as possible
157. ### Summary: Optimization • Existential Type, Opaque Type and Generics are

“specialized” by compiler as possible • Use appropriate ‘some’ and ‘any’ as possible regardless of specialization

160. ### Recap • Existential type and Opaque type evolution • Existential

Container and Performance
161. ### Recap • Existential type and Opaque type evolution • Existential

Container and Performance • Specialization for Generics, Existential type and Opaque type
162. ### Learn more evolution SE-0360 Opaque result types with limited availability

apple/swift-evolution SE-0375 Opening existential arguments to optional parameters SE-0352 Implicitly Opened Existentials SE-0328 Structural opaque result types apple/swift-evolution apple/swift-evolution apple/swift-evolution
163. ### Learn API Design with ‘any’ and ‘some’ Embrace Swift generics

WWDC 22 Design protocol interfaces in Swift WWDC 22
164. ### Other Talks Generic Protocols and Associated types - POWER TOOLS

FOR UNIT TESTING SwiftHeroes 2023 Swift Optimizing (at Compiler World) NSSpain 2020
165. ### Thank you! Yuki ‘freddi’ Aki - iOS Engineer at LINE

• 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