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

    View Slide

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

    View Slide

  3. 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

    View Slide

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

    View Slide

  5. 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

    View Slide

  6. 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

    View Slide

  7. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. 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;
    }

    View Slide

  14. 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,
    }

    View Slide

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

    View Slide

  16. 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;
    }

    View Slide

  17. 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 = [];

    View Slide

  18. 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);
    });
    }

    View Slide

  19. 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 🥷

    View Slide

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

    View Slide

  21. 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, …

    View Slide

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

    View Slide

  23. 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

    View Slide

  24. 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

    View Slide

  25. 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?

    View Slide

  26. 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

    View Slide

  27. 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];

    View Slide

  28. 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]'

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  32. 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);
    }
    });

    View Slide

  33. 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

    View Slide

  34. 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);

    View Slide

  35. 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);

    View Slide

  36. 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);

    View Slide

  37. 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!

    View Slide

  38. 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

    View Slide

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

    View Slide

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

    View Slide

  41. 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) {
    // …
    }

    View Slide

  42. 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;
    }

    View Slide

  43. 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;
    }

    View Slide

  44. 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;
    }

    View Slide

  45. 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;
    }

    View Slide

  46. 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);

    View Slide

  47. 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);

    View Slide

  48. 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);

    View Slide

  49. 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);

    View Slide

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

    View Slide

  51. 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;
    }

    View Slide

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

    View Slide

  53. 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);

    View Slide

  54. 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);

    View Slide

  55. 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);
    }

    View Slide

  56. 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);
    }

    View Slide

  57. 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);
    }

    View Slide

  58. 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);
    }

    View Slide

  59. 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);
    }

    View Slide

  60. 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);

    View Slide

  61. 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),
    };

    View Slide

  62. 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),
    };

    View Slide

  63. 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),
    };

    View Slide

  64. 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);
    }

    View Slide

  65. 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);
    }

    View Slide

  66. 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);
    }

    View Slide

  67. 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);
    }

    View Slide

  68. 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);
    }

    View Slide

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

    View Slide

  70. 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);
    }

    View Slide

  71. 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);
    // }

    View Slide

  72. 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);
    // }

    View Slide

  73. 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);
    // }

    View Slide

  74. 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),
    };

    View Slide

  75. 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,
    };

    View Slide

  76. 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,
    };

    View Slide

  77. 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

    View Slide

  78. 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

    View Slide

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

    View Slide

  80. 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

    View Slide

  81. 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

    View Slide

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

    View Slide

  83. 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

    View Slide

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

    View Slide

  85. 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)

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  90. 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) {…}

    View Slide

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

    View Slide

  92. 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

    View Slide