by Massimiliano Dessì
desmax74@yahoo.com
twitter: @desmax74

and Mario Fusco
mario.fusco@gmail.com
twitter: @mariofusco
Moore's
  law
Now achieved
by increasing
 the number
   of cores


 The number of transistors on integrated
 circuits doubles approximately every two years
Moore's
  law
Now achieved
by increasing
 the number
   of cores


 The number of transistors on integrated
 circuits doubles approximately every two years
Amdahl's
                                      law



The speedup of a program using multiple processors
 in parallel computing is limited by the time needed
      for the sequential fraction of the program
Concurrency & Parallelism
Concurrent programming
Managing concurrent requests




                               Parallel programming
                               Running multiple tasks at
                                   the same time


                Both are too hard!
The cause of the problem …

                  Mutable state +
              Parallel processing =
              Non-determinism
The cause of the problem …

                  Mutable state +
              Parallel processing =
              Non-determinism


                Functional
               Programming
… and its effects



Race conditions
                                      Starvation

 Deadlocks
                                          Livelocks
… and its effects



Race conditions
                                      Starvation

 Deadlocks
                                          Livelocks




    Too hard to think about them!
The native Java concurrency model
   Based on:                      Threads

                                            Semaphores




         Locks                                        Synchronization


They are sometimes plain evil …

                 … and sometimes a necessary pain …

                                       … but always the wrong   default
Different concurrency models



Shared mutable state
  (threads + locks)




                                     Isolated mutable state (actors)


                       Purely immutable (pure functions)
Summing attendants ages (Threads)
class Blackboard {
    int sum = 0;
    int read() { return sum; }
    void write(int value) { sum = value; }
}


                 class Attendant implements Runnable {
                     int age;
                     Blackboard blackboard;

                     public void run() {
                         synchronized(blackboard) {
                             int oldSum = blackboard.read();
                             int newSum = oldSum + age;
                             blackboard.write(newSum);
                         }
                     }
                 }
Summing attendants ages (Actors)
class Blackboard extends UntypedActors {
    int sum = 0;
    public void onReceive(Object message) {
        if (message instanceof Integer) {
            sum += (Integer)message;
        }
    }
}
                          class Attendant {
                              int age;
                              Blackboard blackboard;

                              public void sendAge() {
                                  blackboard.sendOneWay(age);
                              }
                          }
Summing attendants ages (Functional)
class Blackboard {
    final int sum;
    Blackboard(int sum) { this.sum = sum; }
}


class Attendant {
    int age;
    Attendant next;

    public Blackboard addMyAge(Blackboard blackboard) {
        final Blackboard b = new Blackboard(blackboard.sum + age);
        return next == null ? b : next.myAge(b);
    }
}

attendants.foldLeft(new Blackboard(0),
                    (att, b) -> new Blackboard(b.sum + att.age));
What is a functional program?
A program created using only pure functions
No side effects allowed like:
  Reassigning a variable
  Modifying a data structure in place
  Setting a field on an object
                                              }
  Throwing an exception or halting with an error



                                              }
  Printing to the console
  Reading user input
  Reading from or writing to a file
  Drawing on the screen
Functional programming is a restriction on how we
  write programs, but not on what they can do
The OOP/FP dualism
class Bird    OOP vs. …
class Cat {
  def capture(b: Bird): Unit = ...
  def eat(): Unit = ...
}
val cat = new Cat
val bird = new Bird

cat.capture(bird)
cat.eat()
             class Cat
             class Bird
             trait Catch
                             … FP                The story
             trait FullStomach
             def capture(prey: Bird, hunter: Cat): Cat with Catch
             def eat(consumer: Cat with Catch): Cat with FullStomach

             val story = (capture _) andThen (eat _)
             story(new Bird, new Cat)
What is a (pure) function?
A function with input type A and output type B
is a computation which relates every value a of
  type A to exactly one value b of type B such
  that b is determined solely by the value of a




                                  But, if it really is a
                                  function, it will do
                                     nothing else
Referential transparency
An expression e is referentially transparent if for all programs p,
    all occurrences of e in p can be replaced by the result of
 evaluating e, without affecting the observable behavior of p




   A function f is pure if the expression f(x) is referentially
        transparent for all referentially transparent x
RT
String x = "purple";
String r1 = x.replace('p', 't');
String r2 = x.replace('p', 't');
                                                  vs.
String r1 = "purple".replace('p', 't');
    r1: "turtle"
String r2 = "purple".replace('p', 't');
    r2: "turtle"
                                          Non-RT
Immutable            StringBuilder x = new StringBuilder("Hi");
                     StringBuilder y = x.append(", mom");
                     String r1 = y.toString();
      Mutable        String r2 = y.toString();

                     String r1 = x.append(", mom").toString();
 Expression not          r1: "Hi, mom"
replaceable with     String r2 = x.append(", mom").toString();
                         r1: "Hi, mom, mom"
    its result
RT wins

Under a developer point of view:
   Easier to reason about since effects of evaluation are
   purely local
   Use of the substitution model: it's possible to replace a
   term with an equivalent one

Under a performance point of view:
   The JVM is free to optimize the code by safely
   reordering the instructions
   No need to synchronize access to shared data
Immutability

Immutable objects can be shared among
many threads exactly because none of
them can modify it

In the same way immutable (persistent)
data structures can be shared without any
need to synchronize the different threads
accessing them
Persistent Collections



                     5



     3                               8


 E           4               7               9



         E       E       E       E       E       E
Persistent Collections



                         5


2
         3                               8


     E           4               7               9



             E       E       E       E       E       E
Persistent Collections
                                 5



                 3
                                     5


    2
                     3                               8

E       E
             E               4               7               9



                         E       E       E       E       E       E
Persistent Collections
                                  5     New Root


                 3           Old Root
                                       5


    2
                     3                                 8
                                  Shared data
E       E
             E                4                7               9



                         E         E       E       E       E       E
Modularity
class Player {
    String name;   public void declareWinner(Player p) {
    int score;         System.out.println(p.name + " wins!");
}                  }
                   public void winner(Player p1, Player p2) {
                       if (p1.score > p2.score) declareWinner(p1)
                       else declareWinner(p2);
                   }
Modularity
class Player {
    String name;   public void declareWinner(Player p) {
    int score;         System.out.println(p.name + " wins!");
}                  }
                   public void winner(Player p1, Player p2) {
                       if (p1.score > p2.score) declareWinner(p1)
                       else declareWinner(p2);
                   }
                                                      Separate
                                                 computational logic
public Player maxScore(Player p1, Player p2) {    from side effects
    return p1.score > p2.score ? p1 : p2;
}
public void winner(Player p1, Player p2) {
    declareWinner(maxScore(p1, p2));
}
Modularity
class Player {
    String name;   public void declareWinner(Player p) {
    int score;         System.out.println(p.name + " wins!");
}                  }
                   public void winner(Player p1, Player p2) {
                       if (p1.score > p2.score) declareWinner(p1)
                       else declareWinner(p2);
                   }
                                                      Separate
                                                 computational logic
public Player maxScore(Player p1, Player p2) {    from side effects
    return p1.score > p2.score ? p1 : p2;
}
public void winner(Player p1, Player p2) {
    declareWinner(maxScore(p1, p2));
}
          declareWinner(players.reduceLeft(maxScore))

 reuse maxScore to compute the winner among a list of players
Modularity
class Player {
    String name;    public void declareWinner(Player p) {
    int score;          System.out.println(p.name + " wins!");
}                   }
                    public void winner(Player p1, Player p2) {
                        if (p1.score > p2.score) declareWinner(p1)
                        else declareWinner(p2);
                    }
                                                           Separate
                                                      computational logic
public Player maxScore(Player p1, Player p2) {         from side effects
    return p1.score > p2.score ? p1 : p2;
}
public void winner(Player p1, Player p2) {
    declareWinner(maxScore(p1, p2));
}
declareWinner(players.parallel().reduceLeft(maxScore))

       It's trivial to parallelize "internal" iteration
A pure functional core



                            functional
                               core




Any function with side-effects can be split into a pure function at the
core and a pair of functions with side-effect. This transformation can
be repeated to push side-effects to the outer layers of the program.

Why we cannot ignore Functional Programming

  • 1.
    by Massimiliano Dessì desmax74@yahoo.com twitter:@desmax74 and Mario Fusco mario.fusco@gmail.com twitter: @mariofusco
  • 2.
    Moore's law Nowachieved by increasing the number of cores The number of transistors on integrated circuits doubles approximately every two years
  • 3.
    Moore's law Nowachieved by increasing the number of cores The number of transistors on integrated circuits doubles approximately every two years
  • 4.
    Amdahl's law The speedup of a program using multiple processors in parallel computing is limited by the time needed for the sequential fraction of the program
  • 5.
    Concurrency & Parallelism Concurrentprogramming Managing concurrent requests Parallel programming Running multiple tasks at the same time Both are too hard!
  • 6.
    The cause ofthe problem … Mutable state + Parallel processing = Non-determinism
  • 7.
    The cause ofthe problem … Mutable state + Parallel processing = Non-determinism Functional Programming
  • 8.
    … and itseffects Race conditions Starvation Deadlocks Livelocks
  • 9.
    … and itseffects Race conditions Starvation Deadlocks Livelocks Too hard to think about them!
  • 10.
    The native Javaconcurrency model Based on: Threads Semaphores Locks Synchronization They are sometimes plain evil … … and sometimes a necessary pain … … but always the wrong default
  • 11.
    Different concurrency models Sharedmutable state (threads + locks) Isolated mutable state (actors) Purely immutable (pure functions)
  • 12.
    Summing attendants ages(Threads) class Blackboard { int sum = 0; int read() { return sum; } void write(int value) { sum = value; } } class Attendant implements Runnable { int age; Blackboard blackboard; public void run() { synchronized(blackboard) { int oldSum = blackboard.read(); int newSum = oldSum + age; blackboard.write(newSum); } } }
  • 13.
    Summing attendants ages(Actors) class Blackboard extends UntypedActors { int sum = 0; public void onReceive(Object message) { if (message instanceof Integer) { sum += (Integer)message; } } } class Attendant { int age; Blackboard blackboard; public void sendAge() { blackboard.sendOneWay(age); } }
  • 14.
    Summing attendants ages(Functional) class Blackboard { final int sum; Blackboard(int sum) { this.sum = sum; } } class Attendant { int age; Attendant next; public Blackboard addMyAge(Blackboard blackboard) { final Blackboard b = new Blackboard(blackboard.sum + age); return next == null ? b : next.myAge(b); } } attendants.foldLeft(new Blackboard(0), (att, b) -> new Blackboard(b.sum + att.age));
  • 15.
    What is afunctional program? A program created using only pure functions No side effects allowed like: Reassigning a variable Modifying a data structure in place Setting a field on an object } Throwing an exception or halting with an error } Printing to the console Reading user input Reading from or writing to a file Drawing on the screen Functional programming is a restriction on how we write programs, but not on what they can do
  • 16.
    The OOP/FP dualism classBird OOP vs. … class Cat { def capture(b: Bird): Unit = ... def eat(): Unit = ... } val cat = new Cat val bird = new Bird cat.capture(bird) cat.eat() class Cat class Bird trait Catch … FP The story trait FullStomach def capture(prey: Bird, hunter: Cat): Cat with Catch def eat(consumer: Cat with Catch): Cat with FullStomach val story = (capture _) andThen (eat _) story(new Bird, new Cat)
  • 17.
    What is a(pure) function? A function with input type A and output type B is a computation which relates every value a of type A to exactly one value b of type B such that b is determined solely by the value of a But, if it really is a function, it will do nothing else
  • 18.
    Referential transparency An expressione is referentially transparent if for all programs p, all occurrences of e in p can be replaced by the result of evaluating e, without affecting the observable behavior of p A function f is pure if the expression f(x) is referentially transparent for all referentially transparent x
  • 19.
    RT String x ="purple"; String r1 = x.replace('p', 't'); String r2 = x.replace('p', 't'); vs. String r1 = "purple".replace('p', 't'); r1: "turtle" String r2 = "purple".replace('p', 't'); r2: "turtle" Non-RT Immutable StringBuilder x = new StringBuilder("Hi"); StringBuilder y = x.append(", mom"); String r1 = y.toString(); Mutable String r2 = y.toString(); String r1 = x.append(", mom").toString(); Expression not r1: "Hi, mom" replaceable with String r2 = x.append(", mom").toString(); r1: "Hi, mom, mom" its result
  • 20.
    RT wins Under adeveloper point of view: Easier to reason about since effects of evaluation are purely local Use of the substitution model: it's possible to replace a term with an equivalent one Under a performance point of view: The JVM is free to optimize the code by safely reordering the instructions No need to synchronize access to shared data
  • 21.
    Immutability Immutable objects canbe shared among many threads exactly because none of them can modify it In the same way immutable (persistent) data structures can be shared without any need to synchronize the different threads accessing them
  • 22.
    Persistent Collections 5 3 8 E 4 7 9 E E E E E E
  • 23.
    Persistent Collections 5 2 3 8 E 4 7 9 E E E E E E
  • 24.
    Persistent Collections 5 3 5 2 3 8 E E E 4 7 9 E E E E E E
  • 25.
    Persistent Collections 5 New Root 3 Old Root 5 2 3 8 Shared data E E E 4 7 9 E E E E E E
  • 26.
    Modularity class Player { String name; public void declareWinner(Player p) { int score; System.out.println(p.name + " wins!"); } } public void winner(Player p1, Player p2) { if (p1.score > p2.score) declareWinner(p1) else declareWinner(p2); }
  • 27.
    Modularity class Player { String name; public void declareWinner(Player p) { int score; System.out.println(p.name + " wins!"); } } public void winner(Player p1, Player p2) { if (p1.score > p2.score) declareWinner(p1) else declareWinner(p2); } Separate computational logic public Player maxScore(Player p1, Player p2) { from side effects return p1.score > p2.score ? p1 : p2; } public void winner(Player p1, Player p2) { declareWinner(maxScore(p1, p2)); }
  • 28.
    Modularity class Player { String name; public void declareWinner(Player p) { int score; System.out.println(p.name + " wins!"); } } public void winner(Player p1, Player p2) { if (p1.score > p2.score) declareWinner(p1) else declareWinner(p2); } Separate computational logic public Player maxScore(Player p1, Player p2) { from side effects return p1.score > p2.score ? p1 : p2; } public void winner(Player p1, Player p2) { declareWinner(maxScore(p1, p2)); } declareWinner(players.reduceLeft(maxScore)) reuse maxScore to compute the winner among a list of players
  • 29.
    Modularity class Player { String name; public void declareWinner(Player p) { int score; System.out.println(p.name + " wins!"); } } public void winner(Player p1, Player p2) { if (p1.score > p2.score) declareWinner(p1) else declareWinner(p2); } Separate computational logic public Player maxScore(Player p1, Player p2) { from side effects return p1.score > p2.score ? p1 : p2; } public void winner(Player p1, Player p2) { declareWinner(maxScore(p1, p2)); } declareWinner(players.parallel().reduceLeft(maxScore)) It's trivial to parallelize "internal" iteration
  • 30.
    A pure functionalcore functional core Any function with side-effects can be split into a pure function at the core and a pair of functions with side-effect. This transformation can be repeated to push side-effects to the outer layers of the program.