Slide 1

Slide 1 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functional Programming in Dart Pascal Welsch Google Developer Expert CTO at phntm GmbH Co-Founder of wiredash.io Droidcon London 2022 @passsy

Slide 2

Slide 2 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 3

Slide 3 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functional Programming in Dart Pascal Welsch Google Developer Expert CTO at phntm GmbH Co-Founder of wiredash.io Droidcon London 2022 @passsy

Slide 4

Slide 4 text

Functional Programming in Dart by @passsy (Pascal Welsch) PHNTM ['fæntəm] Flutter Agency with 15 Flutter Experts from all across Germany

Slide 5

Slide 5 text

Functional Programming in Dart by @passsy (Pascal Welsch) You won’t learn today - Either, Task - Monads, Functors - Composition, pipelining - Pattern matching - Algebraic data types - Tail-recursion

Slide 6

Slide 6 text

Functional Programming in Dart by @passsy (Pascal Welsch) You’ll learn today Function programming basics: - 🍀 Pure functions - 🥶 Immutable data structures - 🌼 First-class functions - 🌸 High-order functions Outlook what the Dart team is working on

Slide 7

Slide 7 text

Functional Programming in Dart by @passsy (Pascal Welsch) Dart and Functional Programming? “Dart is a class-based, single-inheritance, pure object-oriented programming language.” ECMA-408 - 6. Overview

Slide 8

Slide 8 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 9

Slide 9 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 10

Slide 10 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 11

Slide 11 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 12

Slide 12 text

Functional Programming in Dart by @passsy (Pascal Welsch) List _products = []; SortOrder sortOrder = SortOrder.desc; SortField sortField = SortField.price;

Slide 13

Slide 13 text

Functional Programming in Dart by @passsy (Pascal Welsch) List _products = []; SortOrder sortOrder = SortOrder.desc; SortField sortField = SortField.price; class Product { final String name; final int price; final int originalPrice; final double rating; int get discount => originalPrice - price; }

Slide 14

Slide 14 text

Functional Programming in Dart by @passsy (Pascal Welsch) List _products = []; SortOrder sortOrder = SortOrder.desc; SortField sortField = SortField.price; enum SortOrder { asc, desc, } enum SortField { name, price, discount, rating, }

Slide 15

Slide 15 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 16

Slide 16 text

Functional Programming in Dart by @passsy (Pascal Welsch) SortOrder sortOrder = SortOrder.desc; SortField sortField = SortField.price; List _products = []; … label: InkWell( onTap: () { if (sortField == field) { // same field, just flip the sort order sortOrder = sortOrder.flip(); } else { // field changed, reset sort order sortOrder = SortOrder.desc; sortField = field; }

Slide 17

Slide 17 text

Functional Programming in Dart by @passsy (Pascal Welsch) … label: InkWell( onTap: () { if (sortField == field) { // same field, just flip the sort order sortOrder = sortOrder.flip(); } else { // field changed, reset sort order sortOrder = SortOrder.desc; sortField = field; } // sort the products based on the new sort order // TODO: update _products } List _products = [];

Slide 18

Slide 18 text

Functional Programming in Dart by @passsy (Pascal Welsch) The naive approach Use Dart built-in List.sort([int compare(E a,E b)?]) function Compare products by selected property using Comparable.compareTo(T other): int if (SortField.discount == sortField) { _products.sort((a, b) { return sortOrder == SortOrder.asc ? a.discount.compareTo(b.discount) : b.discount.compareTo(a.discount); }); }

Slide 19

Slide 19 text

Functional Programming in Dart by @passsy (Pascal Welsch) _products.sort((a, b) { switch (sortField) { case SortField.name: return sortOrder == SortOrder.asc ? a.name.compareTo(b.name) : b.name.compareTo(a.name); case SortField.discount: return sortOrder == SortOrder.asc ? a.discount.compareTo(b.discount) : b.discount.compareTo(a.discount); case SortField.price: return sortOrder == SortOrder.asc ? a.price.compareTo(b.price) : b.price.compareTo(a.price); case SortField.rating: return sortOrder == SortOrder.asc ? a.rating.compareTo(b.rating) : b.rating.compareTo(a.rating); } }); Today’s task: Let’s make this code functional 🥷

Slide 20

Slide 20 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functional Programming

Slide 21

Slide 21 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functions Also called: Lambda, Closure, Method, Callback, Routine, Subtypes (but still just functions): top-level, anonymous, predicate, high-order, first-class, …

Slide 22

Slide 22 text

Functional Programming in Dart by @passsy (Pascal Welsch) String formatPrice(int cents) {...} Input Output 12 0.12€ 100 1.00€ 2000 20.00€

Slide 23

Slide 23 text

Functional Programming in Dart by @passsy (Pascal Welsch) MoneyFormatter globalEuroFormatter; String formatPrice(int cents) {...} Input Output 12 + globalEuroFormatter 0.12€ || -,12€ 100 + globalEuroFormatter 1.00€ || 1€ 2000 + globalEuroFormatter 20.00€ || 20,00€ || 20EUR

Slide 24

Slide 24 text

Functional Programming in Dart by @passsy (Pascal Welsch) MoneyFormatter globalEuroFormatter; String formatPrice(int cents) {...} Input Output 12 + globalEuroFormatter 0.12€ || -,12€ + globalEuroFormatter 100 + globalEuroFormatter 1.00€ || 1€ + globalEuroFormatter 2000 + globalEuroFormatter 20.00€ || 20,00€ || 20EUR + globalEuroFormatter

Slide 25

Slide 25 text

Functional Programming in Dart by @passsy (Pascal Welsch) String formatPrice(int cents) {...} 🍀 pure function No side-effects Doesn’t mutate the input Always returns the same result for the same input Does not call an impure function Can be replaced with a lookup table But why?

Slide 26

Slide 26 text

Functional Programming in Dart by @passsy (Pascal Welsch) Pure Function Advantages Can be executed in any order Can be executed in parallel Results can be cached, or pre-computed at compile time Easy to test in isolation Easy to focus on, no surprises Requirement: Only use immutable data structures

Slide 27

Slide 27 text

Functional Programming in Dart by @passsy (Pascal Welsch) 🥶 Immutable data structures final list = [1, 2, 3]; list.add(4); // mutation: Bad // Good: make a copy final copy = [...list, 4];

Slide 28

Slide 28 text

Functional Programming in Dart by @passsy (Pascal Welsch) Immutable data structures final user = User(id: '27', name: 'Pascal', email: 'pascal@welsch.dev'); user.email = 'pascal@phntm.xyz'; // Bad, email is mutable // Better, make a copy final updatedUser = user.copyWith(email: 'pascal@phntm.xyz'); // user.email: 'pascal@welsch.dev' (unchanged) // updatedUser.email: 'pascal@phntm.xyz'

Slide 29

Slide 29 text

Functional Programming in Dart by @passsy (Pascal Welsch) Immutable packages

Slide 30

Slide 30 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 31

Slide 31 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functional Programming Style Avoid mutations Avoid side-effects

Slide 32

Slide 32 text

Functional Programming in Dart by @passsy (Pascal Welsch) _products.sort((a, b) { switch (sortField) { case SortField.name: return sortOrder == SortOrder.asc ? a.name.compareTo(b.name) : b.name.compareTo(a.name); case SortField.discount: return sortOrder == SortOrder.asc ? a.discount.compareTo(b.discount) : b.discount.compareTo(a.discount); case SortField.price: return sortOrder == SortOrder.asc ? a.price.compareTo(b.price) : b.price.compareTo(a.price); case SortField.rating: return sortOrder == SortOrder.asc ? a.rating.compareTo(b.rating) : b.rating.compareTo(a.rating); } });

Slide 33

Slide 33 text

Functional Programming in Dart by @passsy (Pascal Welsch) _products.sort((a, b) { switch (sortField) { case SortField.name: return sortOrder == SortOrder.asc ? a.name.compareTo(b.name) : b.name.compareTo(a.name); case SortField.discount: return sortOrder == SortOrder.asc ? a.discount.compareTo(b.discount) : b.discount.compareTo(a.discount); case SortField.price: return sortOrder == SortOrder.asc ? a.price.compareTo(b.price) : b.price.compareTo(a.price); case SortField.rating: return sortOrder == SortOrder.asc ? a.rating.compareTo(b.rating) : b.rating.compareTo(a.rating); } }); Mutation of _products Access of class property sortOrder

Slide 34

Slide 34 text

Functional Programming in Dart by @passsy (Pascal Welsch) // Extract pure function List sortProducts(List products, SortField sortField, SortOrder sortOrder) { // make a copy, mutation of inputs isn’t pure final copy = products.toList(); copy.sort((a, b) { switch (sortField) { case SortField.name: return sortOrder == SortOrder.asc ? a.name.compareTo(b.name) : b.name.compareTo(a.name); case SortField.discount: case SortField.price: case SortField.rating: // … } }); // return an immutable list return List.unmodifiable(copy); } // Call the pure function _products = sortProducts(_products, sortField, sortOrder);

Slide 35

Slide 35 text

Functional Programming in Dart by @passsy (Pascal Welsch) // Extract pure function List sortProducts(List products, SortField sortField, SortOrder sortOrder) { // ... } // Call the pure function _products = sortProducts(_products, sortField, sortOrder);

Slide 36

Slide 36 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { // make a copy, mutation of inputs isn’t pure final copy = products.toList(); // ... // return an immutable list return List.unmodifiable(copy); } _products = sortProducts(_products, sortField, sortOrder);

Slide 37

Slide 37 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); // Use our existing sort code copy.sort((a, b) { switch (sortField) { case SortField.name: return sortOrder == SortOrder.asc ? a.name.compareTo(b.name) : b.name.compareTo(a.name); case SortField.discount: case SortField.price: case SortField.rating: // … } }); return List.unmodifiable(copy); } _products = sortProducts(_products, sortField, sortOrder); What a nice, pure function!

Slide 38

Slide 38 text

Functional Programming in Dart by @passsy (Pascal Welsch) Pure Function Advantages Can be executed in any order Can be executed in parallel Results can be cached, or pre-computed at compile time Easy to test in isolation Easy to focus on, no surprises

Slide 39

Slide 39 text

Functional Programming in Dart by @passsy (Pascal Welsch) Level 1 completed: You learned the concept of pure functions!

Slide 40

Slide 40 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functions Pascal Welsch

Slide 41

Slide 41 text

Functional Programming in Dart by @passsy (Pascal Welsch) 🌼 High order functions A higher-order function is a function that takes functions as parameters, or returns a function. // Takes a function as input Result myFunction(Function fn) { // … } // Returns a function Function myFunction() { // … } // both, input and output are functions Function myFunction(Function fn) { // … }

Slide 42

Slide 42 text

Functional Programming in Dart by @passsy (Pascal Welsch) // Let’s refactor! List getProductsWith4StarPlusRating() { final List result = []; for (final product in _products) { if (product.rating > 4) { result.add(product); } } return result; }

Slide 43

Slide 43 text

Functional Programming in Dart by @passsy (Pascal Welsch) List getProductsWith4StarPlusRating() { final List result = []; for (final product in _products) { if (product.rating > 4) { result.add(product); } } return result; }

Slide 44

Slide 44 text

Functional Programming in Dart by @passsy (Pascal Welsch) List getProductsWithRating(double minRating) { final List result = []; for (final product in _products) { if (product.rating > minRating) { result.add(product); } } return result; }

Slide 45

Slide 45 text

Functional Programming in Dart by @passsy (Pascal Welsch) List getProductsWith4StarPlusRating() { final List result = []; for (final product in _products) { if (product.rating > 4) { result.add(product); } } return result; }

Slide 46

Slide 46 text

Functional Programming in Dart by @passsy (Pascal Welsch) List getProducts(bool Function(Product) predicate) { final List result = []; for (final product in _products) { if (predicate(product)) { result.add(product); } } return result; } getProducts((product) => product.rating > 4); getProducts((product) => product.rating > 3);

Slide 47

Slide 47 text

Functional Programming in Dart by @passsy (Pascal Welsch) List getProducts(bool Function(Product) predicate) { final List result = []; for (final product in _products) { if (predicate(product)) { result.add(product); } } return result; } getProducts((product) => product.rating > 4); getProducts((product) => product.rating > 3);

Slide 48

Slide 48 text

Functional Programming in Dart by @passsy (Pascal Welsch) List getProducts(bool Function(Product) predicate) { final List result = []; for (final product in _products) { if (predicate(product)) { result.add(product); } } return result; } getProducts((product) => product.rating > 4); getProducts((product) => product.rating > 3); _products.where((product) => product.rating > 4); _products.where((product) => product.rating > 3);

Slide 49

Slide 49 text

Functional Programming in Dart by @passsy (Pascal Welsch) // List getProducts(bool Function(Product) predicate) { // final List result = []; // for (final product in _products) { // if (predicate(product)) { // result.add(product); // } // } // return result; // } // // getProducts((product) => product.rating > 4); // getProducts((product) => product.rating > 3); _products.where((product) => product.rating > 4); _products.where((product) => product.rating > 3);

Slide 50

Slide 50 text

Functional Programming in Dart by @passsy (Pascal Welsch) _products.where((product) => product.rating > 4); _products.where((product) => product.rating > 3);

Slide 51

Slide 51 text

Functional Programming in Dart by @passsy (Pascal Welsch) List getProductsWith4StarPlusRating() { final List result = []; for (final product in _products) { if (product.rating > 4) { result.add(product); } } return result; } List getProductsWith3StarPlusRating() { final List result = []; for (final product in _products) { if (product.rating > 3) { result.add(product); } } return result; }

Slide 52

Slide 52 text

Functional Programming in Dart by @passsy (Pascal Welsch) Isn’t creating lambdas like (product) => product.rating > 4 expensive at scale?

Slide 53

Slide 53 text

Functional Programming in Dart by @passsy (Pascal Welsch) Function references // function as lambda _products.where((product) => product.rating > 4); bool has4StarPlusRating(Product product) { return product.rating > 4; } // function reference _products.where(has4StarPlusRating);

Slide 54

Slide 54 text

Functional Programming in Dart by @passsy (Pascal Welsch) 🌸 Functions as first-class citizens Functions can be stores in variables and data structures and can be passed as arguments or returned from higher-order functions bool has4StarPlusRating(Product product) { return product.rating > 4; } final bool Function(Product) savedFunction = has4StarPlusRating; final List list = [has4StarPlusRating, has3StarPlusRating]; list.add((Product) => true);

Slide 55

Slide 55 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); copy.sort((a, b) { switch (sortField) { case SortField.name: return sortOrder == SortOrder.asc ? a.name.compareTo(b.name) : b.name.compareTo(a.name); case SortField.discount: case SortField.price: case SortField.rating: // … } }); return List.unmodifiable(copy); }

Slide 56

Slide 56 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); // replace switch case with long nested if-else if (SortField.discount == sortField) { if (sortOrder == SortOrder.asc) { copy.sort((a, b) => a.discount.compareTo(b.discount)); } else { copy.sort((a, b) => b.discount.compareTo(a.discount)); } } else { // … } return List.unmodifiable(copy); }

Slide 57

Slide 57 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); if (SortField.discount == sortField) { if (sortOrder == SortOrder.asc) { copy.sort((a, b) => a.discount.compareTo(b.discount)); } else { copy.sort((a, b) => b.discount.compareTo(a.discount)); } } else { // … } return List.unmodifiable(copy); }

Slide 58

Slide 58 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); late int Function(Product a, Product b) compare; if (SortField.discount == sortField) { if (sortOrder == SortOrder.asc) { compare = (a, b) => a.discount.compareTo(b.discount); } else { compare = (a, b) => b.discount.compareTo(a.discount); } } else { // … } copy.sort(compare); return List.unmodifiable(copy); }

Slide 59

Slide 59 text

Functional Programming in Dart by @passsy (Pascal Welsch) _products = sortProducts(_products, sortField, sortOrder); List sortProducts(List products, SortField sortField, SortOrder sortOrder) { // make a copy, mutation of inputs isn’t pure final copy = products.toList(); late int Function(Product a, Product b) compare; if (SortField.discount == sortField) { if (sortOrder == SortOrder.asc) { compare = (a, b) => a.discount.compareTo(b.discount); } else { compare = (a, b) => b.discount.compareTo(a.discount); } } else { // … } copy.sort(compare); // return an immutable list return List.unmodifiable(copy); }

Slide 60

Slide 60 text

Functional Programming in Dart by @passsy (Pascal Welsch) final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; List sortProducts(List products, SortField sortField, SortOrder sortOrder) { // make a copy, mutation of inputs isn’t pure final copy = products.toList(); late int Function(Product a, Product b) compare; if (SortField.discount == sortField) { if (sortOrder == SortOrder.asc) { compare = (a, b) => a.discount.compareTo(b.discount); } else { compare = (a, b) => b.discount.compareTo(a.discount); } } else { // … } copy.sort(compare); // return an immutable list return List.unmodifiable(copy);

Slide 61

Slide 61 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); late int Function(Product a, Product b) compare; if (SortField.discount == sortField) { if (sortOrder == SortOrder.asc) { compare = (a, b) => a.discount.compareTo(b.discount); } else { compare = (a, b) => b.discount.compareTo(a.discount); } } else { // … } copy.sort(compare); return List.unmodifiable(copy); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), };

Slide 62

Slide 62 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); final Function(Product a, Product b) compare = sortFunctionsByFieldAsc[sortField]!; copy.sort(compare); return List.unmodifiable(copy); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), };

Slide 63

Slide 63 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); final Function(Product a, Product b) compare = sortFunctionsByFieldAsc[sortField]!; copy.sort(compare); return List.unmodifiable(copy); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), };

Slide 64

Slide 64 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); var Function(Product a, Product b) compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse; } copy.sort(compare); return List.unmodifiable(copy); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; extension Reverse on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }

Slide 65

Slide 65 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); var Function(Product a, Product b) compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse; } copy.sort(compare); return List.unmodifiable(copy); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; extension Reverse on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }

Slide 66

Slide 66 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { final copy = products.toList(); var Function(Product a, Product b) compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse; } copy.sort(compare); return List.unmodifiable(copy); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; extension Reverse on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }

Slide 67

Slide 67 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse; } return List.unmodifiable(products.toList()..sort(compare)); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; extension Reverse on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }

Slide 68

Slide 68 text

Functional Programming in Dart by @passsy (Pascal Welsch) Vanilla Dart solution List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse; } return List.unmodifiable(products.toList()..sort(compare)); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; extension Reverse on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }

Slide 69

Slide 69 text

Functional Programming in Dart by @passsy (Pascal Welsch) What about functional programming dart packages?

Slide 70

Slide 70 text

Functional Programming in Dart by @passsy (Pascal Welsch) List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse; } return List.unmodifiable(products.toList()..sort(compare)); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; extension Reverse on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }

Slide 71

Slide 71 text

Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:kt_dart/kt.dart'; List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse(); } return List.unmodifiable(products.toList()..sort(compare)); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; // extension Reverse on int Function(T, T) { // int Function(T, T) get reverse => (a, b) => this(b, a); // }

Slide 72

Slide 72 text

Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:kt_dart/kt.dart'; List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse(); } return List.unmodifiable(products.toList()..sort(compare)); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; // extension Reverse on int Function(T, T) { // int Function(T, T) get reverse => (a, b) => this(b, a); // }

Slide 73

Slide 73 text

Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:dartx/dartx.dart'; import 'package:kt_dart/kt.dart'; List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var compare = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { compare = compare.reverse(); } // return List.unmodifiable(products.toList()..sort(compare)); return products.sortedWith(comparator); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), }; // extension Reverse on int Function(T, T) { // int Function(T, T) get reverse => (a, b) => this(b, a); // }

Slide 74

Slide 74 text

Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:dartx/dartx.dart'; import 'package:kt_dart/kt.dart'; List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var comparator = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { comparator = compare.reverse(); } return products.sortedWith(comparator); } final Map sortFunctionsByFieldAsc = { SortField.rating: (a, b) => a.rating.compareTo(b.rating), SortField.name: (a, b) => a.name.compareTo(b.name), SortField.discount: (a, b) => a.discount.compareTo(b.discount), SortField.price: (a, b) => a.price.compareTo(b.price), };

Slide 75

Slide 75 text

Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:dartx/dartx.dart'; import 'package:kt_dart/kt.dart'; List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var comparator = compareBy(fieldSelectors[sortField]!); if (sortOrder == SortOrder.desc) { comparator = comparator.reverse(); } return products.sortedWith(comparator); } final Map fieldSelectors = { SortField.rating: (it) => it.rating, SortField.name: (it) => it.name, SortField.discount: (it) => it.discount, SortField.price: (it) => it.price, };

Slide 76

Slide 76 text

Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:dartx/dartx.dart'; import 'package:kt_dart/kt.dart'; List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var comparator = compareBy(fieldSelectors[sortField]!); if (sortOrder == SortOrder.desc) { comparator = comparator.reverse(); } return products.sortedWith(comparator); } final Map fieldSelectors = { SortField.rating: (it) => it.rating, SortField.name: (it) => it.name, SortField.discount: (it) => it.discount, SortField.price: (it) => it.price, };

Slide 77

Slide 77 text

Functional Programming in Dart by @passsy (Pascal Welsch) _products = sortProducts(_products, sortField, sortOrder); List sortProducts(List products, SortField sortField, SortOrder sortOrder) { var comparator = compareBy(fieldSelectors[sortField]!); if (sortOrder == SortOrder.desc) { comparator = comparator.reverse(); } return products.sortedWith(comparator); } final Map fieldSelectors = { SortField.rating: (it) => it.rating, SortField.name: (it) => it.name, SortField.discount: (it) => it.discount, SortField.price: (it) => it.price, }; Functional darty solution

Slide 78

Slide 78 text

Functional Programming in Dart by @passsy (Pascal Welsch) _products.sort((a, b) { switch (sortField) { case SortField.name: return sortOrder == SortOrder.asc ? a.name.compareTo(b.name) : b.name.compareTo(a.name); case SortField.discount: return sortOrder == SortOrder.asc ? a.discount.compareTo(b.discount) : b.discount.compareTo(a.discount); case SortField.price: return sortOrder == SortOrder.asc ? a.price.compareTo(b.price) : b.price.compareTo(a.price); case SortField.rating: return sortOrder == SortOrder.asc ? a.rating.compareTo(b.rating) : b.rating.compareTo(a.rating); } }); The naive approach

Slide 79

Slide 79 text

Functional Programming in Dart by @passsy (Pascal Welsch) Convinced, that FP is better?

Slide 80

Slide 80 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functional Code >>> Imperative Code Easy to test Pure functions can’t be flaky - by design Easy to debug Easy to refactor Thread-safe by design, easy to parallelize

Slide 81

Slide 81 text

Functional Programming in Dart by @passsy (Pascal Welsch) Is Dart good choice for Functional Programming? Pro - Functions are first-class citizens - one-line lambdas are supported - Immutable references (final) - Generics - Extension functions - Type inference Cons - No immutable collections - No algebraic data types (unions) - No pattern matching - Many dart:core functions have side-effects and throw exceptions - Lambda are quite verbose

Slide 82

Slide 82 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functional Programming - a new tool in your toolbox

Slide 83

Slide 83 text

Functional Programming in Dart by @passsy (Pascal Welsch) Dart and Functional Programming? “Dart is a class-based, single-inheritance, pure object-oriented programming language.” ECMA-408 - 6. Overview

Slide 84

Slide 84 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 85

Slide 85 text

Functional Programming in Dart by @passsy (Pascal Welsch) A bright functional future for Dart? “Patterns and related features” is in the “impl” phase (dart-lang/language/546)

Slide 86

Slide 86 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 87

Slide 87 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 88

Slide 88 text

Functional Programming in Dart by @passsy (Pascal Welsch)

Slide 89

Slide 89 text

Functional Programming in Dart by @passsy (Pascal Welsch) Immutable data structures No official support by Dart. Use kt_dart or fast_immutable_collection

Slide 90

Slide 90 text

Functional Programming in Dart by @passsy (Pascal Welsch) You learned today Function programming basics: - 🍀 Pure functions - no side effects. input -> output - 🥶 Immutable data structures - freezed, kt_dart - 🌼 First-class functions - function are like objects - 🌸 High-order functions // both, input and output can be functions Function myFunction(Function fn) {…}

Slide 91

Slide 91 text

Functional Programming in Dart by @passsy (Pascal Welsch) Do yourself a favour and write more functional code. Thank me later Pascal Welsch 👋

Slide 92

Slide 92 text

Functional Programming in Dart by @passsy (Pascal Welsch) Functional Programming in Dart Pascal Welsch Google Developer Expert CTO at phntm GmbH Co-Founder of wiredash.io Droidcon London 2022 @passsy