Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Sätze für lau

Sätze für lau

Lars Hupel

April 29, 2017
Tweet

More Decks by Lars Hupel

Other Decks in Programming

Transcript

  1. Sätze für lau Die fünf Phasen der Trauer über Type

    Reification Lars Hupel 29. April 2017
  2. Über mich ▶ Doktorand an der Technischen Universität München ▶

    forscht im Bereich der Softwareverifikation ▶ 10-jähriges Konferenzjubiläum 2
  3. Fazit 1. Type Erasure ist nicht schlecht, sondern gut. 2.

    Es gibt zu wenig Type Erasure. 3. Neue Typparameter braucht das Land. 4. In Scala ist alles besser. 3
  4. Java und Generics Java 5 (September 2004) brachte uns Generics.

    ▶ List<String> statt List ▶ list.get(0) statt (String) list.get(0) ▶ Syntax inspiriert von C++ ▶ aber: komplett anders implementiert! 5
  5. Begriffsklärung Typsystem “ A type system is a tractable syntactic

    method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute. ” Benjamin Pierce 14
  6. Begriffsklärung Typsystem “ A type system is a tractable syntactic

    method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute. ” Benjamin Pierce 14
  7. Begriffsklärung Typsystem “ A type system is a tractable syntactic

    method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute. ” Benjamin Pierce 14
  8. Begriffsklärung Typsystem “ A type system is a tractable syntactic

    method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute. ” Benjamin Pierce 14
  9. Begriffsklärung Typsystem “ A type system is a tractable syntactic

    method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute. ” Benjamin Pierce 14
  10. Laufzeittypen 1. Folgerung Der Compiler verwirft Information 2. Folgerung „Laufzeittyp“

    ist ein Widerspruch in sich 3. Folgerung Typdispatching ist zum Scheitern verurteilt 15
  11. Ko- und Kontravarianz Annahme: unveränderliche Collections Java List<Dog> goodDogs =

    new List<Dog>(); List<? extends Animal> goodAnimals = goodDogs; 18
  12. Ko- und Kontravarianz Annahme: unveränderliche Collections Java List<Dog> goodDogs =

    new List<Dog>(); List<? extends Animal> goodAnimals = goodDogs; Scala val goodDogs: List[Dog] = List.empty val goodAnimals: List[Animal] = goodDogs 18
  13. Ko- und Kontravarianz Annahme: unveränderliche Collections Java (“use site”) List<Dog>

    goodDogs = new List<Dog>(); List<? extends Animal> goodAnimals = goodDogs; Scala (“declaration site”) val goodDogs: List[Dog] = List.empty val goodAnimals: List[Animal] = goodDogs 18
  14. Ko- und Kontravarianz Reifizierte Generics führen zu zwei Problemen: 1.

    Festlegung auf “use site”-Varianz 2. Laufzeitprüfung von parametrisierten Subtyp-Beziehungen 19
  15. Situation in Haskell -- Sigh. This is horrible, but then

    so is unsafeCoerce. unsafeCoerce :: a -> b 25
  16. Situation in Haskell -- Sigh. This is horrible, but then

    so is unsafeCoerce. unsafeCoerce :: a -> b -- The type-safe cast operation cast :: (Typeable a, Typeable b) => a -> Maybe b 25
  17. Begriffsklärung Polymorphismus Subtyp-Polymorphismus Die konkrete Methode, die bei einem Aufruf

    obj.f(x) aufgerufen wird, ist erst zur Laufzeit ermittelbar. 27
  18. Begriffsklärung Polymorphismus Subtyp-Polymorphismus Die konkrete Methode, die bei einem Aufruf

    obj.f(x) aufgerufen wird, ist erst zur Laufzeit ermittelbar. Parametrischer Polymorphismus Eine Funktion (oder Klasse) ist nicht nur über Werte, sondern auch über Typen parametrisiert. 27
  19. Begriffsklärung Polymorphismus Subtyp-Polymorphismus Die konkrete Methode, die bei einem Aufruf

    obj.f(x) aufgerufen wird, ist erst zur Laufzeit ermittelbar. Parametrischer Polymorphismus Eine Funktion (oder Klasse) ist nicht nur über Werte, sondern auch über Typen parametrisiert. Ad-hoc-Polymorphismus Die Implementierung einer überladenen Methode (häufig: Operator) wird vom Compiler statisch an Hand der involvierten Typen selektiert. 27
  20. Begriffsklärung Polymorphismus Subtyp-Polymorphismus Die konkrete Methode, die bei einem Aufruf

    obj.f(x) aufgerufen wird, ist erst zur Laufzeit ermittelbar. Parametrischer Polymorphismus Eine Funktion (oder Klasse) ist nicht nur über Werte, sondern auch über Typen parametrisiert. Ad-hoc-Polymorphismus Die Implementierung einer überladenen Methode (häufig: Operator) wird vom Compiler statisch an Hand der involvierten Typen selektiert. 27
  21. Parametrischer Polymorphismus Quellcode def map[A, B](list: List[A], f: A =>

    B): List[B] Signatur public <A, B> List<B> map(List<A>, Function1<A, B>); 29
  22. Parametrischer Polymorphismus Quellcode def map[A, B](list: List[A], f: A =>

    B): List[B] Signatur public <A, B> List<B> map(List<A>, Function1<A, B>); Laufzeit > meth.toString() public List Bla.map(List,Function1) 29
  23. Ad-hoc-Polymorphismus Stark vereinfacht: syntaktisches Überladen trait Number { def +(x:

    Int): Number def +(x: Float): Number def +(x: Number): Number } 30
  24. Mehr Typparameter! Parametrischer Entwurf case class BlogPost[T]( date: Date, title:

    String, author: User, text: T ) Vorteile ▶ BlogPost interessiert sich nicht für den Text: ▶ kodiert (UTF-8) ▶ dekodiert (Codepoints) ▶ internationalisiert (Map[Language, Text]) ▶ escaped (HTML) 33
  25. Mehr Typparameter! Parametrischer Entwurf case class BlogPost[T]( date: Date, title:

    String, author: User, text: T ) Vorteile ▶ Operationen interessieren sich nicht für den Text: ▶ Archivübersicht ▶ Publikation ▶ Bearbeiten von Metadaten 33
  26. Mehr Typparameter! Parametrischer Entwurf case class BlogPost[T]( date: Date, title:

    String, author: User, text: T ) Vorteile ▶ Sätze für lau 33
  27. Sätze für lau ▶ basierend auf „Parametrizität“ ▶ vereinfacht: Funktion

    mit Typparameter weiß nichts und darf nichts Beispiel // Signatur beschreibt exakt eine mögliche Funktion public <T> T id(T t); 34
  28. Sätze für lau ▶ basierend auf „Parametrizität“ ▶ vereinfacht: Funktion

    mit Typparameter weiß nichts und darf nichts Fortgeschrittenes Beispiel // Summary enthält nicht den Text public <T> Html renderSummary(BlogPost<T> post); 34
  29. Sätze für lau ▶ basierend auf „Parametrizität“ ▶ vereinfacht: Funktion

    mit Typparameter weiß nichts und darf nichts Fortgeschrittenes Beispiel // Summary enthält nicht den Text public Html renderSummary(BlogPost<?> post); 34
  30. Sätze für lau ▶ basierend auf „Parametrizität“ ▶ vereinfacht: Funktion

    mit Typparameter weiß nichts und darf nichts Beispiel aus der Bibliothek list.map(f).map(g) == list.map(f andThen g) list.map(f).filter(g) == list.filter(f andThen g).map(f) 34
  31. (Gebundene) Namen sind Schall und Rauch “ What’s in a

    name? that which we call a rose By any other name would smell as sweet ” Shakespeare 36
  32. (Gebundene) Namen sind Schall und Rauch “ What’s in a

    name? that which we call a type parameter By any other name would still be parametric ” Reynolds 36
  33. Verbotene Dinge ▶ null ▶ Exceptions (außer Error, sofern unfangbar)

    ▶ isinstanceof ▶ Casting ▶ equals, toString, hashCode ▶ getClass ▶ globale Seiteneffekte 37
  34. Verbotene Dinge ▶ null ▶ Exceptions (außer Error, sofern unfangbar)

    ▶ isinstanceof ▶ Casting ▶ equals, toString, hashCode ▶ getClass ▶ globale Seiteneffekte 37
  35. Metaprogrammierung “ Metaprogramming is a workaround for an abstraction your

    programming language doesn’t have yet. ” In Java ist Metaprogrammiering (Reflection) grundsätzlich unsicher. 40
  36. Was kann man tun? Lösungsvorschlag ▶ “Super Type Tokens” nach

    Neal Gafter,1 2006 ▶ ermöglicht “Typesafe Heterogeneous Containers” 1https://gafter.blogspot.de/2006/12/super-type-tokens.html 41
  37. Was kann man tun? Lösungsvorschlag ▶ “Super Type Tokens” nach

    Neal Gafter,1 2006 ▶ ermöglicht “Typesafe Heterogeneous Containers” public abstract class TypeToken<T> {} new TypeToken<List<Int>> {} 1https://gafter.blogspot.de/2006/12/super-type-tokens.html 41
  38. Type Tokens in Scala scala> classTag[List[Int]] res0: ClassTag[List[Int]] = List

    scala> typeTag[List[Int]] res1: TypeTag[List[Int]] = TypeTag[List[Int]] 42
  39. Type Tokens in Scala scala> classTag[List[Int]] res0: ClassTag[List[Int]] = List

    scala> typeTag[List[Int]] res1: TypeTag[List[Int]] = TypeTag[List[Int]] scala> def foo[T] = typeTag[T] <console>:17: error: No TypeTag available for T def foo[T] = typeTag[T] scala> def foo[T] = weakTypeTag[T] foo: [T]=> WeakTypeTag[T] 42
  40. In der Praxis? Feststellung Type Erasure ist gut. Problem ▶

    sichere Abhilfen existieren (z.B. Scala) ▶ aber: bringen wenige Vorteile gegenüber Type Reification 44
  41. In der Praxis? Feststellung Type Erasure ist gut. Problem ▶

    sichere Abhilfen existieren (z.B. Scala) ▶ aber: bringen wenige Vorteile gegenüber Type Reification ▶ besser: Entwurfsmuster überdenken 44
  42. Typgetriebene Entwicklung Leitlinien ▶ konkrete Typen vermeiden ▶ Implementation durch

    Typen einschränken ▶ Compiler als Hilfe, nicht als Hindernis ▶ ungültige Zustände unrepräsentierbar machen ▶ “Type Tetris”2 2http://underscore.io/blog/posts/2017/04/11/type-tetris.html 45
  43. new T ▶ gängiges Problem: Erzeugung einer Instanz ▶ Welche

    Instanz? ▶ Wie verhält sich die Instanz? ▶ Welche Parameter? 47
  44. Monoide // Laws: // combine(x, empty) == x // combine(combine(a,

    b), c) == combine(a, combine(b, c)) trait Monoid[T] { def empty: T def combine(t1: T, t2: T): T } 48
  45. Monoide // Laws: // combine(x, empty) == x // combine(combine(a,

    b), c) == combine(a, combine(b, c)) trait Monoid[T] { def empty: T def combine(t1: T, t2: T): T } def mapReduce[A, B : Monoid](list: List[A], f: A => B): B 48
  46. Monoide // Laws: // combine(x, empty) == x // combine(combine(a,

    b), c) == combine(a, combine(b, c)) trait Monoid[T] { def empty: T def combine(t1: T, t2: T): T } def mapReduce[F[_] : Foldable, A, B : Monoid] (as: F[A], f: A => B): B 48
  47. Schlusswort “ Wie kann ich wissen, was ich denke, wenn

    der Compiler es noch nicht überprüft hat? ” Der Franzose 50