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