if you think you can stay away from functional programming, you are wrong

44
by Mario Fusco [email protected] twitter: @mariofusco

Upload: mario-fusco

Post on 15-Jan-2015

2.677 views

Category:

Technology


2 download

DESCRIPTION

 

TRANSCRIPT

Page 1: If You Think You Can Stay Away from Functional Programming, You Are Wrong

by Mario [email protected]: @mariofusco

Page 2: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Moore's

law

The number of transistors on integrated

circuits doubles approximately every two years

Page 3: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Moore's

law

The number of transistors on integrated

circuits doubles approximately every two years

Now achieved

by increasing

the number

of cores

Page 4: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Moore's

law

The number of transistors on integrated

circuits doubles approximately every two years

Now achieved

by increasing

the number

of cores

Page 5: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Fortran

C / C++Java

Lisp

MLHaskell

Add abstractions

C#

Algol

Subtract abstractions

Imperative languages

Functional languages

Scala

F#

Hybrid languages

Page 6: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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

Page 7: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Concurrency & Parallelism

Parallel programmingRunning multiple tasks at

the same time

Concurrent programmingManaging concurrent requests

Both are hard!

Page 8: If You Think You Can Stay Away from Functional Programming, You Are Wrong

The cause of the problem …

Mutable state +

Parallel processing =

Non-determinism

Page 9: If You Think You Can Stay Away from Functional Programming, You Are Wrong

The cause of the problem …

Mutable state +

Parallel processing =

Non-determinism

Functional

Programming

Page 10: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Race conditions

Deadlocks

Starvation

Livelocks

… and its effects

Page 11: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Too hard to think about them!

Race conditions

Deadlocks

Starvation

Livelocks

… and its effects

Page 12: If You Think You Can Stay Away from Functional Programming, You Are Wrong

The native Java concurrency model

Based on:

They are sometimes plain evil …

… and sometimes a necessary pain …

… but always the wrong default

Threads

Semaphores

SynchronizationLocks

Page 13: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Different concurrency models

Isolated mutable state (actors)

Purely immutable (pure functions)

Shared mutable state

(threads + locks)

Page 14: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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

}

}

}

Page 15: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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

}

}

Page 16: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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

}

}

Page 17: If You Think You Can Stay Away from Functional Programming, You Are Wrong

The state quadrantsMutable

Immutable

Shared

Unshared

Actors

Functional

Programming

Threads

Concurrency friendly

Concurrency unfriendly

Page 18: If You Think You Can Stay Away from Functional Programming, You Are Wrong

OOP makes code understandable

by encapsulating moving parts

FP makes code understandable

by minimizing moving parts

- Michael Feathers

OOP vs FP

Page 19: If You Think You Can Stay Away from Functional Programming, You Are Wrong

The OOP/FP dualism - OOPpublic class Bird { }

public class Cat {

private Bird catch;

private boolean full;

public void capture(Bird bird) {

catch = bird;

}

public void eat() {

full = true;

catch = null;

}

}

Cat cat = new Cat();

Bird bird = new Bird();

cat.capture(bird);

cat.eat();

The story

Page 20: If You Think You Can Stay Away from Functional Programming, You Are Wrong

The OOP/FP dualism - FPpublic class Bird { }

public class Cat {

public CatWithCatch capture(Bird bird) { return new CatWithCatch(bird); }

}

public class CatWithCatch {

private final Bird catch;

public CatWithCatch(Bird bird) { catch = bird; }

public FullCat eat() { return new FullCat(); }

}

public class FullCat { }

BiFunction<Cat, Bird, FullCat> story =

((BiFunction<Cat, Bird, CatWithCatch>)Cat::capture)

.compose(CatWithCatch::eat);

FullCat fullCat = story.apply( new Cat(), new Bird() );

Page 21: If You Think You Can Stay Away from Functional Programming, You Are Wrong

The OOP/FP dualism - FPpublic class Bird { }

public class Cat {

public CatWithCatch capture(Bird bird) { return new CatWithCatch(bird); }

}

public class CatWithCatch {

private final Bird catch;

public CatWithCatch(Bird bird) { catch = bird; }

public FullCat eat() { return new FullCat(); }

}

public class FullCat { }

BiFunction<Cat, Bird, FullCat> story =

((BiFunction<Cat, Bird, CatWithCatch>)Cat::capture)

.compose(CatWithCatch::eat);

FullCat fullCat = story.apply( new Cat(), new Bird() );

Immutability

Emphasis on verbs

instead of names

No need to test internal state: correctness enforced by the compiler

Page 22: If You Think You Can Stay Away from Functional Programming, You Are Wrong

for (Employee e : employees) {

e.setSalary(e.getSalary() * 1.03);

}

employees.forEach(e -> e.setSalary(e.getSalary() * 1.03));

Inherently serial

Client has to manage iteration

Nested loops are poorly readable

+ Library is in control � opportunity for internal optimizations as parallelization,

lazy evaluation, out-of-order execution

+ More what, less how � better readability

+ Fluent (pipelined) operations � better readability

+ Client can pass behaviors into the API as data �

possibility to abstract and generalize over behavior �

more powerful, expressive APIs

Not only a syntactic change!

Internal vs External Iteration

Page 23: If You Think You Can Stay Away from Functional Programming, You Are Wrong

� Encourages a pipelined ( "fluent" ) usage style

� Operations are divided between intermediate and terminal

� Lazy in nature: only terminal operations actually trigger a computation

employees.stream()

.filter(e -> e.getIncome() > 50000)

.map(e -> e.getName())

.forEach(System.out::println);

Streams - Efficiency with laziness

Page 24: If You Think You Can Stay Away from Functional Programming, You Are Wrong

� Encourages a pipelined ( "fluent" ) usage style

� Operations are divided between intermediate and terminal

� Lazy in nature: only terminal operations actually trigger a computation

employees.stream()

.filter(e -> e.getIncome() > 50000)

.map(e -> e.getName())

.forEach(System.out::println);

parallelStream()

… and parallelism for free

Streams - Efficiency with laziness

Page 25: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Is there such thing as a free lunch?

Page 26: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Probably yes …

… but we need functional

forks and knives to eat it

Page 27: If You Think You Can Stay Away from Functional Programming, You Are Wrong

�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

A program created using only pure functions

What is a functional program?

No side effects allowed like:

Functional programming is a restriction on how we

write programs, but not on what they can do

}}

Page 28: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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

Page 29: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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

Page 30: If You Think You Can Stay Away from Functional Programming, You Are Wrong

RTString x = "purple";

String r1 = x.replace('p', 't');

String r2 = x.replace('p', 't');

String r1 = "purple".replace('p', 't');

r1: "turtle"

String r2 = "purple".replace('p', 't');

r2: "turtle"

StringBuilder x = new StringBuilder("Hi");

StringBuilder y = x.append(", mom");

String r1 = y.toString();

String r2 = y.toString();

String r1 = x.append(", mom").toString();

r1: "Hi, mom"

String r2 = x.append(", mom").toString();

r1: "Hi, mom, mom"

Non-RT

vs.

Page 31: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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

�Possible to cache the result of time consuming functions

(memoization), e.g. with

Map.computeIfAbsent(K key,

Function<? super K,? extends V> mappingFunction)

Page 32: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Mutability

�Parameter binding is about assigning names to things

�Mutating variables is about assigning things to names

Does that second

one sound weird?

… well it's because

it IS weird

Page 33: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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

Page 34: If You Think You Can Stay Away from Functional Programming, You Are Wrong

5

8

7 9

3

4

EEEEE E

E

Persistent Collections

Page 35: If You Think You Can Stay Away from Functional Programming, You Are Wrong

5

8

7 9

3

4

EEEEE E

E

2

Persistent Collections

Page 36: If You Think You Can Stay Away from Functional Programming, You Are Wrong

5

8

7 9

3

4

EEEEE E

E

5

3

2

EE

Persistent Collections

Page 37: If You Think You Can Stay Away from Functional Programming, You Are Wrong

5

8

7 9

3

4

EEEEE E

E

5

3

2

EE

Shared data

Old Root

New Root

Persistent Collections

Page 38: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Modularityclass Player {

String name;

int score;

}

public void declareWinner(Player p) {

System.out.println(p.name + " wins!");

}

public void winner(Player p1, Player p2) {

if (p1.score > p2.score) declareWinner(p1)

else declareWinner(p2);

}

Page 39: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Modularityclass Player {

String name;

int score;

}

public void declareWinner(Player p) {

System.out.println(p.name + " wins!");

}

public void winner(Player p1, Player p2) {

if (p1.score > p2.score) declareWinner(p1)

else declareWinner(p2);

}

public Player maxScore(Player p1, Player p2) {

return p1.score > p2.score ? p1 : p2;

}

public void winner(Player p1, Player p2) {

declareWinner(maxScore(p1, p2));

}

Separate

computational logic

from side effects

Page 40: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Modularityclass Player {

String name;

int score;

}

public void declareWinner(Player p) {

System.out.println(p.name + " wins!");

}

public void winner(Player p1, Player p2) {

if (p1.score > p2.score) declareWinner(p1)

else declareWinner(p2);

}

public Player maxScore(Player p1, Player p2) {

return p1.score > p2.score ? p1 : p2;

}

public void winner(Player p1, Player p2) {

declareWinner(maxScore(p1, p2));

}

Separate

computational logic

from side effects

declareWinner(players.reduce(maxScore).get())

reuse maxScore to compute the winner among a list of players

Page 41: If You Think You Can Stay Away from Functional Programming, You Are Wrong

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.

Page 42: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Key Takeaways

� Strive for immutability

� Confine side-effects

� Avoid blocking code

� Cede control with higher-order functions

� Leverage referential transparency

� Use FP to design more composable and reusable API

… but there are no dogmas

� Be pragmatic and use the right tool for the job at hand

Poly-paradigm programming is more powerful

and effective than polyglot programming

Page 43: If You Think You Can Stay Away from Functional Programming, You Are Wrong
Page 44: If You Think You Can Stay Away from Functional Programming, You Are Wrong

Mario Fusco

Red Hat – Senior Software Engineer

[email protected]

twitter: @mariofusco

Q A

Thanks … Questions?