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

Getting started with Functional Programming

Getting started with Functional Programming

Object Oriented Programming is on a decline in popularity since 2010, while Functional Programming experience a second hype. Most new languages today are a mix of both, functional and object-oriented.

Dart is an object-oriented language, featuring only some Functional Programming paradigms.

This talk will teach the mindset behind FP and how to use more FP in todays dart code. I will give an outlook to upcoming Dart language features that make FP actually fun to use in Dart!

Pascal Welsch

October 27, 2022
Tweet

More Decks by Pascal Welsch

Other Decks in Programming

Transcript

  1. 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
  2. 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
  3. Functional Programming in Dart by @passsy (Pascal Welsch) PHNTM ['fæntəm]

    Flutter Agency with 15 Flutter Experts from all across Germany
  4. 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
  5. 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
  6. 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
  7. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> _products

    = []; SortOrder sortOrder = SortOrder.desc; SortField sortField = SortField.price;
  8. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> _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; }
  9. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> _products

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

    = SortOrder.desc; SortField sortField = SortField.price; List<Product> _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; }
  11. 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<Product> _products = [];
  12. Functional Programming in Dart by @passsy (Pascal Welsch) The naive

    approach Use Dart built-in List<E>.sort([int compare(E a,E b)?]) function Compare products by selected property using Comparable<T>.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); }); }
  13. 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 🥷
  14. 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, …
  15. Functional Programming in Dart by @passsy (Pascal Welsch) String formatPrice(int

    cents) {...} Input Output 12 0.12€ 100 1.00€ 2000 20.00€
  16. 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
  17. 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
  18. 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?
  19. 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
  20. 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];
  21. Functional Programming in Dart by @passsy (Pascal Welsch) Immutable data

    structures final user = User(id: '27', name: 'Pascal', email: '[email protected]'); user.email = '[email protected]'; // Bad, email is mutable // Better, make a copy final updatedUser = user.copyWith(email: '[email protected]'); // user.email: '[email protected]' (unchanged) // updatedUser.email: '[email protected]'
  22. 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); } });
  23. 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
  24. Functional Programming in Dart by @passsy (Pascal Welsch) // Extract

    pure function List<Product> sortProducts(List<Product> 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);
  25. Functional Programming in Dart by @passsy (Pascal Welsch) // Extract

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

    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);
  27. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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!
  28. 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
  29. Functional Programming in Dart by @passsy (Pascal Welsch) Level 1

    completed: You learned the concept of pure functions!
  30. 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) { // … }
  31. Functional Programming in Dart by @passsy (Pascal Welsch) // Let’s

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

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

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

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

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

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

    Function(Product) predicate) { final List<Product> 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);
  38. Functional Programming in Dart by @passsy (Pascal Welsch) // List<Product>

    getProducts(bool Function(Product) predicate) { // final List<Product> 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);
  39. Functional Programming in Dart by @passsy (Pascal Welsch) _products.where((product) =>

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

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

    lambdas like (product) => product.rating > 4 expensive at scale?
  42. 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);
  43. 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<bool Function(Product)> list = [has4StarPlusRating, has3StarPlusRating]; list.add((Product) => true);
  44. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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); }
  45. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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); }
  46. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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); }
  47. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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); }
  48. Functional Programming in Dart by @passsy (Pascal Welsch) _products =

    sortProducts(_products, sortField, sortOrder); List<Product> sortProducts(List<Product> 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); }
  49. Functional Programming in Dart by @passsy (Pascal Welsch) final Map<SortField,

    int Function(Product a, Product b)> 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<Product> sortProducts(List<Product> 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);
  50. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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<SortField, int Function(Product a, Product b)> 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), };
  51. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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<SortField, int Function(Product a, Product b)> 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), };
  52. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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<SortField, int Function(Product a, Product b)> 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), };
  53. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }
  54. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }
  55. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }
  56. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }
  57. Functional Programming in Dart by @passsy (Pascal Welsch) Vanilla Dart

    solution List<Product> sortProducts(List<Product> 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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }
  58. Functional Programming in Dart by @passsy (Pascal Welsch) List<Product> sortProducts(List<Product>

    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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { int Function(T, T) get reverse => (a, b) => this(b, a); }
  59. Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:kt_dart/kt.dart';

    List<Product> sortProducts(List<Product> 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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { // int Function(T, T) get reverse => (a, b) => this(b, a); // }
  60. Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:kt_dart/kt.dart';

    List<Product> sortProducts(List<Product> 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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { // int Function(T, T) get reverse => (a, b) => this(b, a); // }
  61. Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:dartx/dartx.dart';

    import 'package:kt_dart/kt.dart'; List<Product> sortProducts(List<Product> 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<SortField, int Function(Product a, Product b)> 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<T> on int Function(T, T) { // int Function(T, T) get reverse => (a, b) => this(b, a); // }
  62. Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:dartx/dartx.dart';

    import 'package:kt_dart/kt.dart'; List<Product> sortProducts(List<Product> products, SortField sortField, SortOrder sortOrder) { var comparator = sortFunctionsByFieldAsc[sortField]!; if (sortOrder == SortOrder.desc) { comparator = compare.reverse(); } return products.sortedWith(comparator); } final Map<SortField, int Function(Product a, Product b)> 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), };
  63. Functional Programming in Dart by @passsy (Pascal Welsch) import 'package:dartx/dartx.dart';

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

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

    sortProducts(_products, sortField, sortOrder); List<Product> sortProducts(List<Product> products, SortField sortField, SortOrder sortOrder) { var comparator = compareBy(fieldSelectors[sortField]!); if (sortOrder == SortOrder.desc) { comparator = comparator.reverse(); } return products.sortedWith(comparator); } final Map<SortField, Comparable Function(Product)> fieldSelectors = { SortField.rating: (it) => it.rating, SortField.name: (it) => it.name, SortField.discount: (it) => it.discount, SortField.price: (it) => it.price, }; Functional darty solution
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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)
  71. Functional Programming in Dart by @passsy (Pascal Welsch) Immutable data

    structures No official support by Dart. Use kt_dart or fast_immutable_collection
  72. 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) {…}
  73. Functional Programming in Dart by @passsy (Pascal Welsch) Do yourself

    a favour and write more functional code. Thank me later Pascal Welsch 👋
  74. 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