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

Functional Programming in Dart - A practical approach

Functional Programming in Dart - A practical approach

Functional programming has been a recent trend in the market and has many things to offer for increasing developer productivity. We're going to cover what Functional APIs are available in Dart and how they can help us write clear and concise code.

Spearkers: Samvid Mistry & Tirth Patel

Meet-up: Flutter Ahmedabad April 2019

Tirth Patel

April 13, 2019
Tweet

More Decks by Tirth Patel

Other Decks in Programming

Transcript

  1. Course of talk • Functions & Variables • First class

    & Higher order functions • Lambdas • Code quality and quantity • List APIs
  2. Properties of functions • Purity • Only depends on data

    provided to it • add(a, b) => a + b; //Pure • int a;
 add(b) => a + b; //Impure
  3. Properties of functions • Referential transparency • A function always

    returns the same value on same input, no matter when you call it • add(a,b) => a + b; //transparent • int a;
 add(b) => a + b; //not transparent • a = 5, add(5) => 10; a = 10, add(5) => 15 • Facilitated by purity of functions
  4. Properties of variables • Immutable, final, const. • Functional Programming

    principles are language independent • All math functions are referentially transparent, i.e. Math.sin(s), Math.sqrt(x), Math.max(a,b).
  5. Why, bruh? • Why should variables be immutable? • No

    race conditions. • Less cognitive load. • Why should functions be pure? • Concurrency and parallel evaluation. • Why should functions be referentially transparent? • Lazy evaluation.
  6. First class functions • What does it mean to be

    first class? • First class = type system can make sense of it. • Imperative: a = 5; a = "string"; a = new Object(); • Functional: var f = (a) => (a + 1) • Type: (int) -> int • In general: (parameter_types) -> return_type
  7. Higher order functions • Simply put, it is a function

    which takes function as argument and/or returns a function. • apply(Function f, int a) { return f(a); } • Function createAdder(int a) { return (b) => a + b; } • Function chaining: createAdder(10)(20)
  8. Lambdas • OOP => Inheritance, top-down approach • Functional =>

    composition, bottom-up approach • Naming is one of the biggest problems in programming • Lambda = anonymous function • (param1, param2, ...) => single_statement • (param1, param2, ...) { //multiple statements } • var adder = (a, b) => a + b;
  9. Code quality and quantity • Functional APIs help you write

    less code • Not laziness, but conciseness • More code = More chances of error • APIs = tried, tested and stable code • "Best code is no code at all" - Unknown • "We use code like violence. if it doesn't work, we use more of it" - Venkat Subramaniam
  10. removeWhere List<int> list = List<int>.generate(10, (i) => i); for (int

    i in list) { if (i % 2 == 0) list.remove(i); }
  11. removeWhere List<int> list = List<int>.generate(10, (i) => i); for (int

    i in list) { if (i % 2 == 0) list.remove(i); }
  12. removeWhere List<int> list = List<int>.generate(10, (i) => i); for (int

    i in list) { if (i % 2 == 0) list.remove(i); }
  13. removeWhere List<int> list = List<int>.generate(10, (i) => i); for (int

    i in list) { if (i % 2 == 0) list.remove(i); }
  14. removeWhere List<int> list = List<int>.generate(10, (i) => i); for (int

    i in list) { if (i % 2 == 0) list.remove(i); }
  15. any List<int> list = List<int>.generate(10, (i) => i); bool isFound

    = false; for (int i in list) { if (i % 2 == 0) { isFound = true; break; } } if (isFound) print("Found");
  16. any List<int> list = List<int>.generate(10, (i) => i); bool isFound

    = false; for (int i in list) { if (i % 2 == 0) { isFound = true; break; } } if (isFound) print("Found");
  17. any List<int> list = List<int>.generate(10, (i) => i); bool isFound

    = false; for (int i in list) { if (i % 2 == 0) { isFound = true; break; } } if (isFound) print("Found");
  18. any List<int> list = List<int>.generate(10, (i) => i); bool isFound

    = false; for (int i in list) { if (i % 2 == 0) { isFound = true; break; } } if (isFound) print("Found");
  19. any List<int> list = List<int>.generate(10, (i) => i); bool isFound

    = false; for (int i in list) { if (i % 2 == 0) { isFound = true; break; } } if (isFound) print("Found");
  20. any List<int> list = List<int>.generate(10, (i) => i); bool isFound

    = false; for (int i in list) { if (i % 2 == 0) { isFound = true; break; } } if (isFound) print("Found");
  21. any List<int> list = List<int>.generate(10, (i) => i); list.any((i) =>

    i % 2 == 0) ? print("Found") : print(“Not Found”);
  22. firstWhere List<int> list = List<int>.generate(10, (i) => i); int index

    = -1; for (int i in list) { if (i % 2 == 0) { index = i; break; } } if (index != -1) print("Found ${list[index].toString()}");
  23. firstWhere List<int> list = List<int>.generate(10, (i) => i); int index

    = -1; for (int i in list) { if (i % 2 == 0) { index = i; break; } } if (index != -1) print("Found ${list[index].toString()}");
  24. firstWhere List<int> list = List<int>.generate(10, (i) => i); int index

    = -1; for (int i in list) { if (i % 2 == 0) { index = i; break; } } if (index != -1) print("Found ${list[index].toString()}");
  25. firstWhere List<int> list = List<int>.generate(10, (i) => i); int index

    = -1; for (int i in list) { if (i % 2 == 0) { index = i; break; } } if (index != -1) print("Found ${list[index].toString()}");
  26. firstWhere List<int> list = List<int>.generate(10, (i) => i); int index

    = -1; for (int i in list) { if (i % 2 == 0) { index = i; break; } } if (index != -1) print("Found ${list[index].toString()}");
  27. firstWhere List<int> list = List<int>.generate(10, (i) => i); int index

    = -1; for (int i in list) { if (i % 2 == 0) { index = i; break; } } if (index != -1) print("Found ${list[index].toString()}");
  28. firstWhere List<int> list = List<int>.generate(10, (i) => i); int element

    = list.firstWhere((i) => i % 2 == 0, orElse: () => -1); if(element != -1) { print("Found $element"); }
  29. every List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); bool isAllA = true; for (String follower in followers) { if (!(follower.startsWith("a"))) isAllA = false; } if (isAllA) print("Good to go"); else print("Uh oh");
  30. every List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); bool isAllA = true; for (String follower in followers) { if (!(follower.startsWith("a"))) isAllA = false; } if (isAllA) print("Good to go"); else print("Uh oh");
  31. every List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); bool isAllA = true; for (String follower in followers) { if (!(follower.startsWith("a"))) isAllA = false; } if (isAllA) print("Good to go"); else print("Uh oh");
  32. every List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); bool isAllA = true; for (String follower in followers) { if (!(follower.startsWith("a"))) isAllA = false; } if (isAllA) print("Good to go"); else print("Uh oh");
  33. every List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); bool isAllA = true; for (String follower in followers) { if (!(follower.startsWith("a"))) isAllA = false; } if (isAllA) print("Good to go"); else print("Uh oh");
  34. every List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); bool isAllA = true; for (String follower in followers) { if (!(follower.startsWith("a"))) isAllA = false; } if (isAllA) print("Good to go"); else print("Uh oh");
  35. every List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); if(followers.every((s) => s.startsWith("a"))) print("Good to go"); else print("Uh oh");
  36. join List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); StringBuffer buffer = StringBuffer(); for (int i = 0; i < followers.length; i++) { if (i == followers.length - 1) buffer.write(followers[i]); else buffer.write(followers[i] + ", "); } print(buffer.toString());
  37. join List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); StringBuffer buffer = StringBuffer(); for (int i = 0; i < followers.length; i++) { if (i == followers.length - 1) buffer.write(followers[i]); else buffer.write(followers[i] + ", "); } print(buffer.toString());
  38. join List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); StringBuffer buffer = StringBuffer(); for (int i = 0; i < followers.length; i++) { if (i == followers.length - 1) buffer.write(followers[i]); else buffer.write(followers[i] + ", "); } print(buffer.toString());
  39. join List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); StringBuffer buffer = StringBuffer(); for (int i = 0; i < followers.length; i++) { if (i == followers.length - 1) buffer.write(followers[i]); else buffer.write(followers[i] + ", "); } print(buffer.toString());
  40. join List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); StringBuffer buffer = StringBuffer(); for (int i = 0; i < followers.length; i++) { if (i == followers.length - 1) buffer.write(followers[i]); else buffer.write(followers[i] + ", "); } print(buffer.toString());
  41. join List<String> followers = List<String>.generate(10, (i) => "a".padLeft((i % 2)

    * 5, "z")); StringBuffer buffer = StringBuffer(); for (int i = 0; i < followers.length; i++) { if (i == followers.length - 1) buffer.write(followers[i]); else buffer.write(followers[i] + ", "); } print(buffer.toString());
  42. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { double sum = 0; for (Employee e in employees) { sum += e.salary; } return sum / employees.length; }
  43. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { double sum = 0; for (Employee e in employees) { sum += e.salary; } return sum / employees.length; }
  44. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { double sum = 0; for (Employee e in employees) { sum += e.salary; } return sum / employees.length; }
  45. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { double sum = 0; for (Employee e in employees) { sum += e.salary; } return sum / employees.length; }
  46. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { double sum = 0; for (Employee e in employees) { sum += e.salary; } return sum / employees.length; }
  47. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { double sum = 0; for (Employee e in employees) { sum += e.salary; } return sum / employees.length; }
  48. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { double sum = 0; for (Employee e in employees) { sum += e.salary; } return sum / employees.length; }
  49. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { return employees.fold(0, (s, e) => s + e.salary) / employees.length; }
  50. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { return employees.fold(0, (s, e) => s + e.salary) / employees.length; }
  51. fold List<Employee> employees = List.generate( 10, (i) => new Employee("a".padRight(i

    + 1, "z"), i * 1000)); employees.shuffle(); print(averageSalary(employees)); double averageSalary(List<Employee> employees) { return employees.fold(0, (s, e) => s + e.salary) / employees.length; }
  52. employees.fold(0, (s, e) => s + e.salary) Employee { name:

    a salary: 0 } Employee { name: az salary: 1000 } Employee { name: azz salary: 2000 } 0
  53. employees.fold(0, (s, e) => s + e.salary) Employee { name:

    a salary: 0 } Employee { name: az salary: 1000 } Employee { name: azz salary: 2000 } 0
  54. employees.fold(0, (s, e) => s + e.salary) Employee { name:

    a salary: 0 } Employee { name: az salary: 1000 } Employee { name: azz salary: 2000 } 0
  55. employees.fold(0, (s, e) => s + e.salary) Employee { name:

    a salary: 0 } Employee { name: az salary: 1000 } Employee { name: azz salary: 2000 } 0
  56. employees.fold(0, (s, e) => s + e.salary) Employee { name:

    az salary: 1000 } Employee { name: azz salary: 2000 } Employee { name: azzz salary: 30 } 0
  57. employees.fold(0, (s, e) => s + e.salary) Employee { name:

    az salary: 1000 } Employee { name: azz salary: 2000 } Employee { name: azzz salary: 30 } 0
  58. 1000 employees.fold(0, (s, e) => s + e.salary) Employee {

    name: az salary: 1000 } Employee { name: azz salary: 2000 } Employee { name: azzz salary: 30 }
  59. 1000 employees.fold(0, (s, e) => s + e.salary) Employee {

    name: azz salary: 2000 } Employee { name: azzz salary: 3000 } Employee { name: azzz salary: 40 }
  60. 1000 employees.fold(0, (s, e) => s + e.salary) Employee {

    name: azz salary: 2000 } Employee { name: azzz salary: 3000 } Employee { name: azzz salary: 40 }
  61. 3000 employees.fold(0, (s, e) => s + e.salary) Employee {

    name: azz salary: 2000 } Employee { name: azzz salary: 3000 } Employee { name: azzz salary: 40 }
  62. 3000 employees.fold(0, (s, e) => s + e.salary) Employee {

    name: azzz salary: 3000 } Employee { name: azzzz salary: 4000 } Employee { name: azzz salary: 50 }
  63. Fold as (almost) universal function • employees.max()
 employees.fold(0, (s, e)

    => (e.salary > s) ? e.salary : s) • employees.any(predicate)
 employees.fold(false, (s, e) => 
 (s == false) ? predicate(e) : true) • employees.every(predicate)
 employees.fold(true, (s, e) =>
 (s == true) ? predicate(e) : false)
  64. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  65. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  66. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  67. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  68. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  69. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  70. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  71. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  72. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { List<String> names = List<String>(); for (Employee e in employees) { names.add(e.name.replaceRange(0, 1, e.name[0].toUpperCase())); } return names; }
  73. map List<Employee> employees = List.generate(10, (i) => Employee("a".padRight(i + 1,

    "z"), i * 1000)); employees.shuffle(); print(capitalize(employees)); List<String> capitalize(List<Employee> employees) { return employees .map((e) => e.name.replaceRange(0, 1, e.name[0].toUpperCase())).toList(); }
  74. where List<int> numbers = List.generate(10, (i) => i); for (int

    number in numbers) { if (number % 2 == 1) { print("$number is odd"); } } for (int number in numbers) { if (number % 2 == 0) { print("$number is even"); } }
  75. where List<int> numbers = List.generate(10, (i) => i); for (int

    number in numbers) { if (number % 2 == 1) { print("$number is odd"); } } for (int number in numbers) { if (number % 2 == 0) { print("$number is even"); } }
  76. where List<int> numbers = List.generate(10, (i) => i); for (int

    number in numbers) { if (number % 2 == 1) { print("$number is odd"); } } for (int number in numbers) { if (number % 2 == 0) { print("$number is even"); } }
  77. where List<int> numbers = List.generate(10, (i) => i); for (int

    number in numbers) { if (number % 2 == 1) { print("$number is odd"); } } for (int number in numbers) { if (number % 2 == 0) { print("$number is even"); } }
  78. where List<int> numbers = List.generate(10, (i) => i); for (int

    number in numbers) { if (number % 2 == 1) { print("$number is odd"); } } for (int number in numbers) { if (number % 2 == 0) { print("$number is even"); } }
  79. where List<int> numbers = List.generate(10, (i) => i); for (int

    number in numbers) { if (number % 2 == 1) { print("$number is odd"); } } for (int number in numbers) { if (number % 2 == 0) { print("$number is even"); } }
  80. where List<int> numbers = List.generate(10, (i) => i); for (int

    number in numbers) { if (number % 2 == 1) { print("$number is odd"); } } for (int number in numbers) { if (number % 2 == 0) { print("$number is even"); } }
  81. where List<int> numbers = List.generate(10, (i) => i); for (int

    number in numbers) { if (number % 2 == 1) { print("$number is odd"); } } for (int number in numbers) { if (number % 2 == 0) { print("$number is even"); } }
  82. where List<int> numbers = List.generate(10, (i) => i); numbers .where((number)

    => number % 2 == 1) .forEach((number) => print("$number is odd")); numbers .where((number) => number % 2 == 0) .forEach((number) => print("$number is even"));
  83. words.txt art bread dartisan mart data dartium earth datamart eggs

    state of the art dart spinach dart rider part