Structural Prototypes A Sane Framework for Statically-Typed OO+FP
Avoiding Religion • We’re doing static typing, like it or not! • Assume with me that OO is good • Expressiveness is good • More expressiveness is better?
Class Types
Parametric Polymorphism Class Types
Declaration Site Variance Parametric Polymorphism Class Types
Existentials Declaration Site Variance Parametric Polymorphism Class Types
n o i t a c fi i t n a u Q d e d n Existentials u o B Declaration Site Variance Parametric Polymorphism Class Types
P n a o t i h t a c fi i t n a u Q Dependent d e d n Existentials u o B Declaration Site Variance Parametric Polymorphism Class Types
P n a o t i h t a c fi i t n a u Q Dependent d Higher Kinds e d n Existentials u o B Declaration Site Variance Parametric Polymorphism Class Types
P n a o t i h t a c fi i t n a u Q Dependent d Higher Kinds e d n Existentials u o B Declaration Site Variance Parametric Polymorphism Class Types
FP Makes It Worse… • Higher-Kinds are really necessary
FP Makes It Worse… • Higher-Kinds are really necessary • Typeclasses • (and a zillion resolution strategies)
FP Makes It Worse… • Higher-Kinds are really necessary • Typeclasses • (and a zillion resolution strategies) • Higher-Rank polymorphism
FP Makes It Worse… • Higher-Kinds are really necessary • Typeclasses • (and a zillion resolution strategies) • Higher-Rank polymorphism • Functional utility methods
Turing Completeness • Higher-Kinds give us simply-typed λ -calculus
Turing Completeness • Higher-Kinds give us simply-typed λ -calculus • Object-Orientation implies open recursion
Turing Completeness • Higher-Kinds give us simply-typed λ -calculus • Object-Orientation implies open recursion • Path-dependent types reify open recursion • Escapes object context!
Turing Completeness • Higher-Kinds give us simply-typed λ -calculus • Object-Orientation implies open recursion • Path-dependent types reify open recursion • Escapes object context! • Type-Level Fixpoint
Scala is Inevitable!
y t i l i b a d i c e d n U Scala is Inevitable!
Starting over…
Hindley-Milner • Not particularly powerful (read: expressive)
Hindley-Milner • Not particularly powerful (read: expressive) • Lots of significant limitations • And yet, it’s still very popular!
Hindley-Milner • Not particularly powerful (read: expressive) • Lots of significant limitations • And yet, it’s still very popular! • Hindley-Milner is Good Enough™
What is Object-Orientation?
What is Object-Orientation? • Message Passing • Open Recursion
What is Object-Orientation? • Message Passing • Open Recursion … O O > S O L C y l t n e r a p p a
Simplify, Simplify • Q: What is the simplest way to encode objects? • (hint: it’s not π -calculus)
Simplify, Simplify • Q: What is the simplest way to encode objects? • (hint: it’s not π -calculus) • A: Records of functions
Simplify, Simplify • Q: What is the simplest way to encode objects? • (hint: it’s not π -calculus) • A: Records of functions • Primitive self pointer
What is Functional?
What is Functional? λ
Simplify, Simplify • Q: What’s the simplest way to encode lambdas?
Simplify, Simplify • Q: What’s the simplest way to encode lambdas? • A: Uh…with lambdas?
Simplify, Simplify • Q: What’s the simplest way to encode lambdas? • A: Uh…with lambdas? • Let-bound polymorphism
Putting It Together • Records of lambdas
Putting It Together • Records of lambdas • Primitive self pointer
Putting It Together • Records of lambdas • Primitive self pointer • Let-bound polymorphism • (requires extension for objects)
Putting It Together • Records of lambdas • Primitive self pointer • Let-bound polymorphism • (requires extension for objects) • Principal typing
Structural Prototypes • We only have records, no classes • Object abstraction must be prototypical
Structural Prototypes • We only have records, no classes • Object abstraction must be prototypical • Record types are fully-structural • Not quite OCaml!
Structural Prototypes • We only have records, no classes • Object abstraction must be prototypical • Record types are fully-structural • Not quite OCaml! • Full expressivity of both FP and OO
Structural Prototypes • We only have records, no classes • Object abstraction must be prototypical • Record types are fully-structural • Not quite OCaml! • Full expressivity of both FP and OO • Very simple and orthogonal
Apricot = Origin.with( sweetness: 7 bites: 0 takeBite: #(this.with(bites: bites + 1))) Grapefruit = Apricot.with(sweetness: 1) Apple = Apricot.with(sweetness: 5)
Some = #(x, Origin.with( getOrElse: #(_, x) map: #(f, Some(f(x))) flatMap: #(f, f(x)))) None = Origin.with( getOrElse: #(x, x) map: #(_, this) flatMap: #(_, this))
Seq = #(foldRight, Origin.with( builder: #(xs, Seq(xs.foldRight)) foldRight: foldRight map: #(f, res = foldRight(Vector0, #(x, acc, acc.prepend(f(x)))))))
Seq = #(foldRight, Origin.with( builder: #(xs, Seq(xs.foldRight)) foldRight: foldRight map: #(f, res = foldRight(Vector0, #(x, acc, acc.prepend(f(x))))))) ListImpl = #(foldRight, Seq(foldRight).with( builder: #(xs, xs.foldRight(Nil, Cons)))) Cons = #(head, tail, foldRight = #(z, f, f(head, tail.foldRight(z, f))) ListImpl(foldRight)) Nil = ListImpl(#(_, z, z))
Vector = #(xs, ds = Origin.with( /* hard core data structure */ ) Seq(ds.foldRight).with( builder: Vector prepend: #(x, … ))) Vector0 = … // empty vector
Problems • Structural subtyping is usually tricky • Error messages • Branded types?
Problems • Structural subtyping is usually tricky • Error messages • Branded types? • Prototypes are not always fantastic
Problems • Structural subtyping is usually tricky • Error messages • Branded types? • Prototypes are not always fantastic • Let-bound polymorphism is very restrictive
Is this the Future? • I don’t know (probably not) • We need to keep trying! • Static typing is very hard • …complicated • …and divisive
Questions?
Recommend
More recommend