This talk at the 2015 Function Swift Conference summarized challenges with Swift's Protocols With Associated Types, the reasons for their behavior, their roots in features from other languages, how to workaround issues, and whether to expect them to change.
9. Questions
1. How are PATs weird?
2. Why are PATs weird?
3. Is this the plan?
4. How to love them?
10. How PATs are weird
W1. Only usable as generic constraints
11. Weirdness 1: only usable as generic constraints
• This rule excludes PATs from literally every single use of
"protocols" as defined in Objective-C
12. Weirdness 1: only usable as generic constraints
• This rule excludes PATs from literally every single use of
"protocols" as defined in Objective-C
• Everywhere you wanted a protocol, you need a generic:
From: var delegate:Proto
To: class C<T:Proto> { var delegate:T } }
13. Weirdness 1: only usable as generic constraints
• This rule excludes PATs from literally every single use of
"protocols" as defined in Objective-C
• Everywhere you wanted a protocol, you need a generic:
From: var delegates:[Proto]
To: class C<T:Proto> { var delegates:[T] } }
• Which still excludes dynamic dispatch … which might be
why you wanted a protocol to begin with!
14. How PATs are weird
W2. Docs describe them as "real" types
17. Weirdness 3: the mysterious typealias
typealias serves two different functions:
1. Outside PATs: provides the syntactic convenience of
meaningful names
2. Inside PATs, establishes a semantic requirement on types
adopting the PAT
18. Weirdness 3: the mysterious typealias
• typealias defines a placeholder for an unknown type ...
• ... which can be used throughout the protocol definition
protocol Animal {
typealias Food
func eat(food:Food) { }
}
This sounds familiar...
19. Weirdness 3: the mysterious typealias
typealias feels like a generic type parameter!
struct Animal<Food> {
func eat(food:Food) { }
}
protocol Animal {
typealias Food
func eat(food:Food) { }
}
20. Are PATs just generic protocols
with whacky syntax??
Does that explain everything?!
26. But why not use generic protocol syntax?
/// imaginary generic protocol swift
protocol Animal<Food> {
func eat(food:Food)
}
extension Cow : Animal<Grass> {
func eat(f:Grass) { }
}
27. But why not use generic protocol syntax?
• Because from outside the protocol, consumers could only
see the associated type by parameterizing over it:
/// generic-protocol-swift
func feedAnimal<A:Animal<F>,F>(a:A) {
// I see an F, and oh yeah F is a type variable for food
}
• But Swift PATs provide direct named access to associated
type, like properties
func feedAnimal<A:Animal>(a:A) {
// I see the assoc type: A.Food
}
28. But why not use generic protocol syntax?
And this problem compounds when protocols:
• have many associated types
• which might themselves be constrained by protocols
• and we want to use them all at once
30. Generic Graph BFS in C++
template <class G, class C, class Vis>
void breadth_first_search(const G& g,
typename graph traits<G>::vertex s, C c, Vis vis);
// constraints:
// G models Vertex List Graph and Incidence Graph
// C models Read/Write Map
// map traits<C>::key == graph traits<G>::vertex
// map traits<C>::value models Color
// Vis models BFS Visitor
31. Generic Graph BFS in Haskell (Hugs 2002)
breadth_first_search ::
(VertexListGraph g v, IncidenceGraph g e v,
ReadWriteMap c v Color, BFSVisitor vis a g e v) =>
g ! v ! c ! vis ! a ! a
39. Two Worlds of Protocols
Without Self Requirement With Self Requirement
func precedes(other: Ordered) -> Bool func precedes(other: Self) -> Bool
Usable as a type
func sort(inout a: [Ordered])
Only usable as a generic constraint
func sort<T : Ordered>(inout a: [T])
Think“heterogeneous” Think“homogeneous”
Every model must deal with all others Models are free from interaction
Dynamic dispatch Static dispatch
Less optimizable More optimizable
45. Questions
1. How are PATs weird?
2. Why are PATs weird?
3. Is this the plan?
4. How to love them?
46. Answers
How PATs are weird
• Lock you into generics and static dispatch
• typealias syntax plays two roles
• Associated type is as much like a required property as like a
type parameter
47. Answers
Why PATs are weird
• Rich, multi-type abstractions do not "fit" in OOP subtyping
• Designed to address known issues with naive "generic
protocol" designs (complexity scales badly with more
associated types)
48. Answers
Yes, functioning as planned
• Seems informed by C++ concepts, Haskell type classes, SML
signatures, generics in C# and Java, abstract type members
in Scala, etc.
• Impact on OOP "protocol" pattern: collateral damage
• Existentials?
51. Answers
How to love them
• Call them PATs
• Embrace generics
• If you still need dynamic dispatch
• use enums to push runtime variation into values
• use type erasure to hide dynamic dispatch within a type
• wait for existentials?