JVM Functional Language Battle Orientation in Objects GmbH Weinheimer Str. 68 68309 Mannheim www.oio.de [email protected] Version: 1.0 Ihr Sprecher Falk Sippach (@sippsack) Trainer, Berater, Entwickler Architektur Agile Softwareentwicklung Codequalität Co-Organisator Feedback gern an: @sippsack, [email protected] © Orientation in Objects GmbH JVM Functional Language Battle 2 1 Java, XML und Open Source seit 1998 ) Software Factory ) ) Object Rangers ) • Schlüsselfertige Realisierung von Java Software • Unterstützung laufender • Individualsoftware • Pilot- und Migrationsprojekte • Sanierung von Software • Software Wartung • Perfect Match • Rent-a-team • Coaching on the project • Inhouse Outsourcing © Orientation in Objects GmbH Java Projekte ) Competence Center) • Schulungen, Coaching, Weiterbildungsberatung, Train & Solve-Programme • Methoden, Standards und Tools für die Entwicklung von offenen, unternehmensweiten Systemen JVM Functional Language Battle 3 Abstract Funktionale Programmierung soll so viel ausdrucksstärker sein, aber leider ist dieses Programmier-Paradigma nicht ganz kompatibel zu der prozedural- und objektorientierten Denkweise von uns Java-Entwicklern. Anhand eines kleinen Algorithmus werden wir uns verschiedene Lösungen zunächst im klassischem imperativen Java (vor Java 8) und als Vergleich dazu in alternativen JVM-Sprachen (Groovy, Frege, ggf. Scala bzw. JavaScript) anschauen und die verschiedenen Lösungen diskutieren. Herauskommen soll eine saubere und verständlichere Struktur, die zu besser les- und wartbarem Code führen wird. Die gewonnenen Erkenntnisse wollen wir dann letztendlich in Java 8 mittels Streams und Lambda-Ausdrücken umsetzen, so dass jeder Zuhörer die Grundideen der funktionalen Programmierung mit in seine tägliche Arbeit nehmen kann. Es sind keine speziellen Vorkenntnisse in den angesprochenen alternativen Sprachen notwendig, ein solides Verständnis für die Programmiersprache Java genügt. © Orientation in Objects GmbH JVM Functional Language Battle 4 2 Gliederung • Warum von Imperativ zu Funktional? • Sprachwettkampf • Functional Java 8+ © Orientation in Objects GmbH JVM Functional Language Battle Java Groovy Imperativ © Orientation in Objects GmbH 5 Scala JavaScript Haskell Frege Funktional JVM Functional Language Battle 6 3 Imperativ Funktional Foto von tomwieden, CC0 Public Domain Lizenz, https://pixabay.com/de/boule-kugeln-spielen-frankreich-141004/ © Orientation in Objects GmbH Foto von Mohamed Nuzrath, CC0 Public Domain Lizenz, https://pixabay.com/de/kick-martial-arts-krieger-185384/ JVM Functional Language Battle 7 Problemstellung Foto von Manfred Antranias Zimmer, CC0 Public Domain Lizenz, https://pixabay.com/de/aussichtspunkt-fernrohr-ferne-sicht-1021337/ © Orientation in Objects GmbH JVM Functional Language Battle 8 4 Foto von Media Publishing, CC0 Public Domain Lizenz, https://pixabay.com/de/kreditkarte-kredit-karte-bank-geld-1680347/ © Orientation in Objects GmbH JVM Functional Language Battle 9 Prüfsummen-Berechnung Luhn-Algorithmus rein clientseitige Prüfung möglich Luhn-Formel "Modulo 10"-Algorithmus Double-Add-Double-Methode © Orientation in Objects GmbH JVM Functional Language Battle 10 5 Beispiel 4716347184862961 1 4 2 3 7 1 6 3 1 6 9 2 1 12 9 4 4 1 1 2 9 5 1 3 9 6 4 7 1 8 6 8 6 16 4 6 4 6 4 8 6 2 9 6 1 4 8 4 16 1 7 4 3 6 1 7 4 1 14 4 6 6 2 7 8 1 6 4 7 4 1 6 1 1 4 4 6 6 2 7 8 7 1 5 4 6 6 2 7 8 1+3+9+4+6+7+4+7+1+5+4+6+6+2+7+8 80 80 % 10 == 0 gültig 7 © Orientation in Objects GmbH JVM Functional Language Battle 11 Der Kampf beginnt Foto von Marco Montoya, CC0 Public Domain Lizenz, https://pixabay.com/de/ajedrez-k%C3%B6nig-schach-spiel-640386/ © Orientation in Objects GmbH JVM Functional Language Battle 12 6 © Orientation in Objects GmbH JVM Functional Language Battle 13 JVM Functional Language Battle 14 Java klassisch – Variante 1 © Orientation in Objects GmbH 7 Java klassisch – Variante 2 Variablen Schleifen Verzweigungen Tiefe der Verschachtelung Zustandsänderungen Reihenfolge nicht beliebig ExceptionHandling? © Orientation in Objects GmbH JVM Functional Language Battle 15 OOP? SRP? DRY? SoC? Lesbarkeit? Testbarkeit? Wartbarkeit? Erweiterbarkeit? Wiederverwendbarkeit? Parallelisierbarkeit? Foto von Christopher Kuszajewski, CC0 Public Domain Lizenz, https://pixabay.com/en/source-code-code-programming-c-583537/ © Orientation in Objects GmbH JVM Functional Language Battle 16 8 Java klassisch mit sprechenden Methodennamen © Orientation in Objects GmbH JVM Functional Language Battle • 17 Folge von Statements – mit Schleifen, Verzweigungen, Sprüngen Typische Eigenschaften • Verändern von Zuständen (Variablen) • Vermischung von Was und Wie (bei Schleifen) • Exceptions = Goto-Statements • Vorsicht bei Nebenläufigkeit Foto von tomwieden, CC0 Public Domain Lizenz, https://pixabay.com/de/boule-kugeln-spielen-frankreich-141004/ © Orientation in Objects GmbH JVM Functional Language Battle 18 9 Funktional https://twitter.com/mariofusco/status/571999216039542784 © Orientation in Objects GmbH JVM Functional Language Battle 19 Java klassisch – Spaghetti-Code Aufspalten in Ziffern Reihenfolge drehen Jede 2. Ziffer verdoppeln Aufsummieren Validierungsprüfung © Orientation in Objects GmbH JVM Functional Language Battle 20 10 Imperativ Funktional https://twitter.com/mariofusco/status/571999216039542784 © Orientation in Objects GmbH JVM Functional Language Battle 21 Wie sieht es in anderen Sprachen aus? Foto von Marco Montoya, CC0 Public Domain Lizenz, https://pixabay.com/de/ajedrez-k%C3%B6nig-schach-spiel-640386/ © Orientation in Objects GmbH JVM Functional Language Battle 22 11 Groovy • objektorientiert • dynamisch typisiert (statisch auch möglich) • ausdrucksstarke/prägnante Syntax • sehr gute Integration mit Java (JVM, Bibliotheken, Vererbung, …) • Metaprogrammierung, Closures, Operatorüberladung • Funktionsliterale (Closures) sind First Class Citizens © Orientation in Objects GmbH JVM Functional Language Battle 23 JVM Functional Language Battle 24 Beispiele in Groovy © Orientation in Objects GmbH 12 JavaScript • objektorientierte Skriptsprache • aber klassenlos (Prototyp-basiert) • dynamisch typisiert • Funktionen sind First Class Citizens • geeignet für Client (Browser) und Server (Node.js, Nashorn) © Orientation in Objects GmbH JVM Functional Language Battle 25 JVM Functional Language Battle 26 Beispiel JavaScript © Orientation in Objects GmbH 13 Kotlin • statisch typisiert • objektorientiert • Übersetzung in Java Bytecode oder JavaScript Quellcode • interoperabel mit Java • entwickelt bei Jetbrains (IntelliJ IDEA) © Orientation in Objects GmbH JVM Functional Language Battle 27 JVM Functional Language Battle 28 Beispiel Kotlin © Orientation in Objects GmbH 14 Kurz, kürzer, lesbarer? http://codegolf.eu-west-1.elasticbeanstalk.com/results © Orientation in Objects GmbH JVM Functional Language Battle 29 Viele Beispiele in vielen imperativen Sprachen später … Foto von Marco Montoya, CC0 Public Domain Lizenz, https://pixabay.com/de/ajedrez-k%C3%B6nig-schach-spiel-640386/ © Orientation in Objects GmbH JVM Functional Language Battle 30 15 Frege • Haskell for the JVM • rein funktionale Programmiersprache • statisch typisiert mit Typinferenz und Typvariablen • frei von Nebeneffekten • Monaden zur Kapselung von imperativen Konstrukten • Pattern Matching • Typklassen JVM Functional Language Battle © Orientation in Objects GmbH 31 Beispiel 4716347184862961 1 4 7 2 1 6 3 1 12 4 1 1 2 5 1 3 6 6 2 9 in 6Ziffern 1 Aufsplitten 3 6 1 7 Ziffern umdrehen4 9 4 6 16 4 16 1 14 4 jede 6 2. 6 verdoppeln 2 7 8 9 4 6 1 6 4 1 6 1 1 4 4 Ziffern 6 6 aufspalten 2 7 8 9 4 6 7 4 7 1 5 4 Teilsummen 6 6 2 7 8 1 + 3 + 9 + 4 + 6 + 7 + 4 + 7 + 1 + 5 + 4 + 6 +Aufsummieren 6+2+7+8 1 6 3 4 7 1 8 4 8 9 2 6 8 4 8 1 7 4 80 80 % 10 == 0 gültig 7 © Orientation in Objects GmbH Teilbar durch 10? JVM Functional Language Battle 32 16 Algorithmus in Frege isValid n = Validierungsfunktion divisibleBy10( Teilbar durch 10? sumDigits( Aufsummieren double2nd( jede 2. verdoppeln reverse( Ziffern umdrehen toDigits(n) Aufsplitten in Ziffern ) ) ) ) JVM Functional Language Battle © Orientation in Objects GmbH 33 toDigits reverse double2nd sumDigits true false divisible10 Funktionskaskade n isValid n = divisibleBy10(sumDigits(double2nd(reverse(toDigits(n))))) © Orientation in Objects GmbH JVM Functional Language Battle 34 17 • • • • Typische Eigenschaften Foto von Mohamed Nuzrath, CC0 Public Domain Lizenz, https://pixabay.com/de/kick-martial-arts-krieger-185384/ © Orientation in Objects GmbH • • • • • • • • Immutability pure/seiteneffektfrei referentielle Transparenz Funktionen als First-ClassCitizens Higher-Order Functions Lambdas/Closures Lazy Evaluation Rekursion Pattern Matching Currying/Partial Function Application Function Composition … JVM Functional Language Battle 35 Funktionale Elemente toDigits n | n < 0 = error "n must be 0 or greater" toDigits 0 = [] toDigits n = toDigits (n `div` 10) ++ [(n `mod` 10)] double2nd = zipWith (\x y -> x * y) (cycle [1, 2]) sumDigits xs = sum (concat (map toDigits xs)) divisibleBy10 n = n `mod` 10 == 0 isValid = divisibleBy10 . sumDigits . double2nd . reverse . toDigits © Orientation in Objects GmbH JVM Functional Language Battle 36 18 Funktionale Elemente toDigits n | n < 0 = error "n must be 0 or greater" toDigits 0 = [] toDigits n = toDigits (n `div` 10) ++ [(n `mod` 10)] double2nd = zipWith (\x y -> x * y) (cycle [1, 2]) sumDigits xs = sum (concat toDigits xs)) Infix- statt(map Postfix-Notation divisibleBy10 n = n `mod` 10 == 0 isValid = divisibleBy10 . sumDigits . double2nd . reverse . toDigits © Orientation in Objects GmbH JVM Functional Language Battle 37 Funktionale Elemente toDigits n | n < 0 = error "n must be 0 or greater" toDigits 0 = [] toDigits n = toDigits (n `div` 10) ++ [(n `mod` 10)] double2nd = zipWith (\x y -> x * y) (cycle [1, 2]) sumDigits xs = sum (concat (map toDigits xs)) Composition: divisibleBy10 nFunction = n `mod` 10 == 0 f . g (x) == f(g(x)) isValid = divisibleBy10 . sumDigits . double2nd . reverse . toDigits © Orientation in Objects GmbH JVM Functional Language Battle 38 19 Funktionale Elemente toDigits n | n < 0 = error "n must be 0 or greater" toDigits 0 = [] toDigits n = toDigits (n `div` 10) ++Lazy [(nEvaluation `mod` 10)] Lambda-Ausdruck double2nd = zipWith (\x y -> x * y) (cycle [1, 2]) Partial Function sumDigits xs = sumHigher (concat toDigits xs)) Order(map Function Persistente Application Datenstrukturen divisibleBy10 n = n `mod` 10 == 0 isValid = divisibleBy10 . sumDigits . double2nd . reverse . toDigits © Orientation in Objects GmbH JVM Functional Language Battle 39 Funktionale Elemente toDigits n | n < 0 = error "n must be 0 or greater" toDigits 0 = [] toDigits n = toDigits (n `div` 10) ++ [(n `mod` 10)] double2nd = zipWith (\x y -> x * y) (cycle [1, 2]) Pattern Matching Rekursion sumDigits xs = sum (concat (map toDigits xs)) divisibleBy10 n = n `mod` 10 == 0 isValid = divisibleBy10 . sumDigits . double2nd . reverse . toDigits © Orientation in Objects GmbH JVM Functional Language Battle 40 20 Funktionale Elemente toDigits n | n < 0 = error "n must be 0 or greater" toDigits 0 = [] toDigits n = toDigits (n `div` 10) ++ [(n `mod` 10)] double2nd = zipWith (\x y -> x * y) (cycle [1, 2]) sumDigits xs = sum (concat (map toDigits xs)) divisibleBy10 n = n `mod` 10 == 0 isValid = divisibleBy10 . sumDigits . double2nd . reverse . toDigits JVM Functional Language Battle © Orientation in Objects GmbH Vorteile • leicht verständlich, einfach zu schlussfolgern • seiteneffektfrei • einfach test-/debugbar • leicht parallelisierbar • modularisierbar und einfach wieder zusammenführbar • hohe Code-Qualität 41 Foto von Mohamed Nuzrath, CC0 Public Domain Lizenz, https://pixabay.com/de/kick-martial-arts-krieger-185384/ © Orientation in Objects GmbH JVM Functional Language Battle 42 21 OO vs. Funktional https://twitter.com/mariofusco/status/63573247425384448 https://twitter.com/mfeathers/status/29581296216 © Orientation in Objects GmbH JVM Functional Language Battle 43 Scala • funktional und objektorientiert • statisch typisiert (Typinferenz) • Funktionen als First-Class-Citizens • Pattern Matching • Java-Integration möglich © Orientation in Objects GmbH JVM Functional Language Battle 44 22 Beispiel Scala © Orientation in Objects GmbH JVM Functional Language Battle 45 Ist Java 8 funktional? Foto von Marco Montoya, CC0 Public Domain Lizenz, https://pixabay.com/de/ajedrez-k%C3%B6nig-schach-spiel-640386/ © Orientation in Objects GmbH JVM Functional Language Battle 46 23 Luhn-Algorithmus in Java 8 – Variante 1 © Orientation in Objects GmbH JVM Functional Language Battle 47 Luhn-Algorithmus in Java 8 – Variante 2 nach Idee von Thomas Much © Orientation in Objects GmbH JVM Functional Language Battle 48 24 Luhn-Algorithmus in Java 8 Variante 1 (vs. Variante 1.1) vs. Variante 2 // 1 if length even, 2 otherwise int[] i = { number.length() % 2 == 0 ? 1 : 2 }; … .map(n -> n * (i[0] = i[0] == 1 ? 2 : 1)) Verkappte Zustandsänderung // oder Ref<Boolean> alternate = new Ref(false); // .map(n -> n * (alternate.swap() ? 2 : 1)) PrimitiveIterator.OfInt faktor = IntStream.iterate(1, i -> 3 - i).iterator(); System.out.println(faktor.nextInt()); // 1 System.out.println(faktor.nextInt()); // 2 Lazy Evaluation System.out.println(faktor.nextInt()); // 1 Generator System.out.println(faktor.nextInt()); // 2 © Orientation in Objects GmbH JVM Functional Language Battle 49 Was heißt "Funktional Programmieren" in Java 8? • Lambdas: Funktionsliterale als First-Class-Citizens • Higher-Order Functions (map, forEach) • Currying und Funktionskomposition • Unendliche Datenstrukturen mit Streams • (Rekursion) © Orientation in Objects GmbH JVM Functional Language Battle 50 25 Java 8: Wiederverwendung von Funktionen Funktionskomposition Verketten/Komposition von Teil-Funktionen: (f . g)(x) == f(g(x)) © Orientation in Objects GmbH JVM Functional Language Battle 51 Java 8: Wiederverwendung von Funktionen Currying und partielle Funktionsaufrufe Currying: Konvertierung einer Funktion mit n Argumenten in n Funktionen mit jeweils einem Argument. Partielle Aufrufe: Spezialisierung von allgemeinen Funktionen © Orientation in Objects GmbH JVM Functional Language Battle 52 26 Was fehlt Java 8 zur besseren funktionalen Unterstützung? • Erzwingen von Immutability • persistente/unveränderbare Datenstrukturen • Vermeidung von Seiteneffekten (erzwingen) • Lazy Evualation • kein echtes Currying • funktionale Bibliotheksfunktionen • Value-Types (Tuple, Either, Try, Validation, Lazy …) © Orientation in Objects GmbH JVM Functional Language Battle 53 Luhn-Algorithmus in Java 8 – Variante 3 Frege/Haskell Style © Orientation in Objects GmbH JVM Functional Language Battle 54 27 Funktionale Erweiterungen für Java Project Lombok © Orientation in Objects GmbH JVM Functional Language Battle 55 Project Lombok • Compile-Time Metaprogrammierung • Reducing Boilerplate Code durch Annotationen • Generation des Immutable-Gerüsts mit @Value • Lazy Evaluierung mit @Getter(lazy = true) © Orientation in Objects GmbH JVM Functional Language Battle 56 28 private, final, keine Setter, Argument-Konstruktor equals/hashcode Lazy-Evaluierung © Orientation in Objects GmbH JVM Functional Language Battle 57 FunctionalJava • funktionale Programmierbibliothek für Java • Lernplattform für funktionale Programmierung mit der gewohnten Sprache • unterstützt Java 6+ (mit Retro Lambda) • Basis Datenstrukturen (Funktionen, partielle Funktionen, Unit, Void, Option, Either, … • Immutable Collections (Array, List, Stream, Set, Map, …) • Monaden, Zipper © Orientation in Objects GmbH JVM Functional Language Battle 58 29 Luhn-Algorithmus in Java 8 mit Functional Java © Orientation in Objects GmbH JVM Functional Language Battle 59 Vavr • "Vavr core is a functional library for Java 8+." • Persistent Data Structures – LinkedList, Queue, Sorted Set, Stream • Tuple, Values (Option, Try, Lazy, Either, …) • Pattern Matching • Functions, CheckedFunctions, Lifting (Exceptions fangen) – Currying, Partial Application, Composition • Monaden, Zipping, … © Orientation in Objects GmbH JVM Functional Language Battle 60 30 http://www.vavr.io/vavr-docs/ © Orientation in Objects GmbH JVM Functional Language Battle 61 JVM Functional Language Battle 62 Vavr: Tuple (bis Tuple8) © Orientation in Objects GmbH 31 Vavr: Wiederverwendung von Funktionen Currying © Orientation in Objects GmbH JVM Functional Language Battle 63 Vavr: Wiederverwendung von Funktionen Partielle Funktionsaufrufe und Komposition © Orientation in Objects GmbH JVM Functional Language Battle 64 32 Vavr: Function Lift (Fangen von Exceptions) © Orientation in Objects GmbH JVM Functional Language Battle 65 Luhn-Algorithmus in Java 8 mit Vavr © Orientation in Objects GmbH JVM Functional Language Battle 66 33 Luhn-Algorithmus in Java 8 mit Vavr (Variante 2) © Orientation in Objects GmbH JVM Functional Language Battle 67 Fazit Foto von Marco Montoya, CC0 Public Domain Lizenz, https://pixabay.com/de/ajedrez-k%C3%B6nig-schach-spiel-640386/ © Orientation in Objects GmbH JVM Functional Language Battle 68 34 Imperativ: Wie erreiche ich mein Ziel? Funktional: Was will ich erreichen? Foto von tomwieden, CC0 Public Domain Lizenz, https://pixabay.com/de/boule-kugeln-spielen-frankreich-141004/ © Orientation in Objects GmbH Foto von Mohamed Nuzrath, CC0 Public Domain Lizenz, https://pixabay.com/de/kick-martial-arts-krieger-185384/ JVM Functional Language Battle 69 Foto von Hans Braxmeier, CC0 Public Domain Lizenz, https://pixabay.com/de/teller-suppenteller-essteller-1365805/ © Orientation in Objects GmbH JVM Functional Language Battle 70 35 + Project Lombok © Orientation in Objects GmbH JVM Functional Language Battle 71 Links • Code-Beispiele – https://github.com/sippsack/jvm-functional-language-battle • Learn You a Haskell for Great Good! – http://learnyouahaskell.com/chapters • LYAH (Learn You a Haskell) adaptions for Frege – https://github.com/Frege/frege/wiki/LYAH-adaptions-for-Frege • Onlinekurs TU Delft (FP 101): – https://courses.edx.org/courses/DelftX/FP101x/3T2014/info © Orientation in Objects GmbH JVM Functional Language Battle 72 36 Links • Vavr – http://www.vavr.io/ • Immutables – http://immutables.github.io/ • Project Lombok – https://projectlombok.org/ • Functional Java – http://www.functionaljava.org/ JVM Functional Language Battle © Orientation in Objects GmbH 73 Literaturhinweise • Functional Programming in Java: Harnessing the Power Of Java 8 Lambda Expressions – Venkat Subramaniam – The Pragmatic Programmers, Erscheinungsdatum: Februar 2014 – ISBN: 978-1-93778-546-8 – Sprache: Englisch • Mastering Lambdas – – – – – © Orientation in Objects GmbH Maurice Naftalin Oracle Press Erscheinungsdatum: Oktober 2014 ISBN: 0071829628 Sprache: Englisch JVM Functional Language Battle 74 37 Literaturhinweise • Learn You a Haskell for Great Good!: A Beginner's Guide – – – – • Miran Lipovaca No Starch Press, Erscheinungsdatum: April 2011 ISBN: 978-1593272838 Sprache: Englisch Real World Haskell – – – – Bryan O'Sullivan und John Goerzen O'Reilly, Erscheinungsdatum: 2010 ISBN: 978-0596514983 Sprache: Englisch JVM Functional Language Battle © Orientation in Objects GmbH 75 ? ? ? ? ? ? ? ? Fragen ? Orientation in Objects GmbH Weinheimer Str. 68 68309 Mannheim www.oio.de [email protected] 76 38 Vielen Dank für Ihre Aufmerksamkeit ! Orientation in Objects GmbH Weinheimer Str. 68 68309 Mannheim www.oio.de [email protected] 39