Upcoming SlideShare
×

A well-typed program never goes wrong

3,574

Published on

Published in: Technology, News & Politics
1 Like
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

Views
Total Views
3,574
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
0
0
Likes
1
Embeds 0
No embeds

No notes for slide

A well-typed program never goes wrong

1. 1. A well-typed program never goes wrong<br />julien@kaching.com<br />Silicon Valley Code Camp 2010<br />
2. 2. µ-Java<br />Imagine Java deprived of <br />all native types and <br />all control-flow constructs<br />
3. 3. Encoding ℕ in µ-Java<br />A number is either<br />zero or<br />the successor of another number<br />
4. 4. Encoding ℕ in µ-Java<br />interface Number { }<br />class Zero implements Number { }<br />class Successor implements Number {<br />privatefinal Number predecessor;<br /> Successor(Number predecessor) {<br />this.predecessor = predecessor;<br /> }<br />}<br />
5. 5. Encoding ℕ in µ-Java<br />Number zero = new Zero();<br />Number one = new Successor(zero);<br />Number two = new Successor(one);<br />
6. 6. Encoding ℕ in µ-Java<br />Number zero = new Zero();<br />Number one = new Successor(zero);<br />Number two = new Successor(one);<br />Number three = one.plus(two);<br />
7. 7. Encoding ℕ in µ-Java<br />interface Number { <br /> Number plus(Number that);<br />}<br />
8. 8. Encoding ℕ in µ-Java<br />class Zero implements Number { <br />public Number plus(Number that) {<br /> }<br />}<br />
9. 9. Encoding ℕ in µ-Java<br />class Zero implements Number { <br />public Number plus(Number that) {<br />return that;<br /> }<br />}<br />
10. 10. Encoding ℕ in µ-Java<br />classSuccessor implementsNumber { <br />privatefinal Number predecessor;<br /> Successor(Number predecessor) {<br />this.predecessor = predecessor;<br />}<br />public Number plus(Number that) {<br /> }<br />}<br />
11. 11. Encoding ℕ in µ-Java<br />classSuccessor implementsNumber { <br />privatefinal Number predecessor;<br /> Successor(Number predecessor) {<br />this.predecessor = predecessor;<br />}<br />public Number plus(Number that) {<br />returnnew Successor(predecessor.plus(that));<br /> }<br />}<br />
12. 12. Encoding ℕ in µ-Java<br />Base case:<br /> 0 + n = n<br />Recurrence:<br /> m + n = ((m - 1) + n) + 1<br />
13. 13. Growing a Language<br />µ-Java<br />expressiveness<br />
14. 14. Today’s Agenda<br />Practical discussion of Type Safety.<br />Grow your language to make it safer.<br />
15. 15. “I’ve written well-typed programs before, <br /> and they went wrong!”<br />
16. 16. This will definitely go wrong<br />scala> defdivide(a: Int, b: Int) = a / b<br />divide: (a: Int,b: Int)Int<br />
17. 17. This will definitely go wrong<br />scala> defdivide(a: Int, b: Int) = a / b<br />divide: (a: Int,b: Int)Int<br />scala> divide(4, 0)<br />java.lang.ArithmeticException: / by zero<br />at .divide(<console>:5)<br />
18. 18. Was it well-typed?<br />
19. 19. Was it well-typed?<br />Yes, but the types didn’t fully convey the complexity of the domain.<br />The type checker doesn’t know you can’t divide by 0 unless it is expressed by the types.<br />How can you grow the language to address this issue?<br />
20. 20. Division by zero, revisited<br />scala> abstractclass Number(n: Int)<br />scala> caseclass Zero extends Number(0)<br />scala> caseclassNonZero(n: Int) extends Number(n)<br />scala> def number(n: Int) = if (n == 0) Zero elseNonZero(n)<br />
21. 21. Division by zero, revisited<br />scala> abstractclass Number(n: Int) {<br />def divide(that: NonZero) = number(n / that.n)<br />}<br />scala> number(4).divide(Zero)<br />
22. 22. Division by zero, revisited<br />scala> abstractclass Number(n: Int) {<br />def divide(that: NonZero) = number(n / that.n)<br />}<br />scala> number(4).divide(Zero)<br />error: type mismatch;<br /> found : Zero<br /> required: NonZero<br />
23. 23. Type Safety<br />The extent to which a programming language discourages or prevents type errors.<br />A type error is erroneous program behavior caused by a discrepancy between differing data types.<br />
24. 24. Well-typed programs never go wrong<br />Preservation <br />Well typednessof programs remains invariant under the transition rules of the language. <br />Progress <br />A well typed program never gets into a state where no further transitions are possible. <br />
25. 25. Value Types<br />Represents possibly infinite set of similarly kinded data transcending an application's life.<br />Life cycles are meaningless.<br />Value types are immutable.<br />Usually restrict the universe of their underlying types.<br />
26. 26. Value Types<br />classEmailAddressextends Value<String> { …<br />classPrice extends Value<Long> { …<br />class Id<E extends Entity> extends Value<Long> { …<br />
27. 27. The 1:1 Principle<br />booleanplaceLimitOrder(Action, Integer, String, Long);<br />booleanplaceLimitOrder(Action, Quantity, Ticker, Price);<br />
28. 28. Type Safe Bit Field<br />Apple's ticker AAPL.<br />What about Berkshire Hathaway’s? <br />Google says BRKA,<br />Yahoo! BRK-A,<br />Bloomberg BRK/A and <br />Reuters BRKa.<br />
29. 29. Type Safe Bit Field<br />interfaceSecurityTag {<br />  interfaceGoogle extendsSecurityTag{}<br />  interfaceYahoo extendsSecurityTag{}<br />  interfaceBloomberg extendsSecurityTag{}<br />  interfaceReuters extendsSecurityTag{}<br />}<br />
30. 30. Type Safe Bit Field<br />classTaggedTicker<T extendsSecurityTag> <br />extends Value<String> { ...<br />
31. 31. Type Safe Bit Field<br />Price getPriceFromGoogle(<br />TaggedTicker<Google> ticker) { ...<br /> <br />voidsendBuyOrderToBloomberg(<br />TaggedTicker<Bloomberg> ticker, Quantity quantity) { ..<br />
32. 32. Type Safe Bit Field<br />interface Security {<br /> <T extendsSecurityTag> TaggedTicker<T><br />getTaggedTicker(Class<T> kind);<br />}<br />
33. 33. Type Safe Bit Field<br />Map<Class<? extendsSecurityTag>, Long> TAG2MASK = <br />ImmutableMap.<br /> <Class<? extendsSecurityTag>, Long> builder()<br />     .put(SecurityTag.Google.class, 0x01)<br />     .put(SecurityTag.Yahoo.class, 0x02)<br />     .put(SecurityTag.Bloomberg.class, 0x04)<br />     .put(SecurityTag.Reuters.class, 0x08)<br />     .build();<br />
34. 34. Type Safe Bit Field<br /><T extendsSecurityTag> void set(Class<T> kind) {<br /> tags = (tags | TAG2MASK.get(kind));<br />}<br /><T extendsSecurityTag> void unset(Class<T> kind) {<br /> tags = (tags & ~TAG2MASK.get(kind));<br />}<br />
35. 35. Invariant Map<br />A bunch of methods in java.util.Map are contravariant on the key type.<br />This makes refactorings extremely error prone.<br />java.util.Map#get(Object)<br />java.util.Map#remove(Object)<br />java.util.Map#containsKey (Object)<br />
36. 36. Invariant Map<br />voiddoSomething(Map<Ticker, Quote> cache) {<br /> …<br />cache.remove(ticker); <br />
37. 37. Invariant Map<br />voiddoSomething(Map<Isin, Quote> cache) { <br /> …<br />cache.remove(ticker);<br />
38. 38. Invariant Map<br />interfaceInvariantMap<K, V> { <br /> V get(K key);<br /> V remove(K key);<br /> ...<br />
39. 39. Invariant Map<br />classInvariantMaps{<br />static<K, V> InvariantMap<K, V> newHashMap() {<br />returndelegate(newHashMap<K, V>());<br /> }<br />static<K extends Comparable<? super K>, V> <br />InvariantMap<K, V> newTreeMap() {<br />returndelegate(newTreeMap<K, V>());<br /> }<br /> …<br />
40. 40. Option<br />abstractclass Option[T]<br />caseclass None extends Option[Nothing]<br />caseclass Some(x: T) extends Option[T]<br />getUser(id) match {<br />case Some(user) ⇒ …<br />case None ⇒ …<br />}<br />
41. 41. Option<br />Much more verbose in Java...<br />getUser(id).visit(newOptionVisitor<Unit>() {<br />public Unit caseSome(User user) {<br /> …<br />publicUnit caseNone() {<br /> …<br />})<br />
42. 42. Option<br />… but still useful!<br />interfaceUserRepository {<br /> Option<User> getUser(Id<User> id);<br />User getUserOrThrow(Id<User> id);<br />}<br />
43. 43. Abstracting the Control Flow<br />We saw how to grow a language by introducing more types.<br />We can also improve control flow structuresby abstracting the control flow.<br />
44. 44. Abstracting the Control Flow<br />BigDecimal total = ZERO;<br />for (BigDecimal value : values) {<br />if (value.compareTo(ZERO) > 0) {<br />total.add(value);<br /> }<br />}<br />return total;<br />
45. 45. Abstracting the Control Flow<br />returnsum(filter(<br /> values, <br />new Predicate<BigDecimal>() {<br />publicboolean apply(BigDecimal t) {<br />return t.compareTo(ZERO) > 0; <br /> }<br /> }));<br />
46. 46. Abstracting the Control Flow<br />Easier to re-use operations.<br />The “wiring” between operations is checked by the type system.<br />
47. 47. References<br />Foundations for Programming Languages<br />John C. Mitchell<br />I Can Has Invariant Mapz?<br />http://eng.kaching.com/2010/07/i-can-has-invariant-mapz.html<br />Type Safe Bit Fields Using Higher-KindedPolymorphism<br /> http://eng.kaching.com/2010/08/type-safe-bit-fields-using-higher.html<br />