SlideShare a Scribd company logo
Functional Programming
Elsevier 2016-07-26
Prashant Kalkar
VTW Senior software developer
Shortcoming of current model.
What is Functional Programming (FP).
Benefits of Functional Programming.
Explore side effects and eliminate them.
Higher order functions and lambda expressions.
Collection processing in FP.
Declarative Programming.
Some more benefits in FP.
FP vs OO and when to use them.
Agenda
Takeaways
What is FP.
Why to use FP.
Initiate the thinking in FP.
Techniques to eliminate side effects.
Structure of functional code base.
Structural difference between FP and OO
When to use FP solution.
When to use OO solution.
Shortcomings of current
model
(with examples)
Consider Example
int f() {
y = y + 1; return y;
}
What is the output of function call
f()?
Requires or depends on
external state.
Need to know the history of
interactions with the
system.
Multiple calls will cause side
effects.
y = 1 // initial value
Now what will be the output?
State of Ellipse
Ellipse ellipse = new Ellipse(new Rectangle(0, 0, 100, 100));
BoundingBox boundingBox = ellipse.boundingBox;
boundingBox.inflate(10, 10);
Mutation in object graph affect many graph objects
Tracking change is difficult.
boolean hitMonster = monster.hitByShooting(gunShot);
boolean hitPlayer = player.hitByShooting(gunShot);
Are these statements independent of each other?
Mutation impose order.
Solutions?
Clause of issue was mutation in the programs. More
precisely global mutation.
Let put in some constrains on functions
Only depend on the input parameters.
For same input, same output.
No mutation of state.
int f(int y) { return y + 1; }
Now what will be the output of functional call f(5)?
Ellipse ellipse = new Ellipse(new Rectangle(0, 0, 100, 100));
BoundingBox boundingBox = ellipse.boundingBox;
boundingBox.inflate(10, 10);
If everything is immutable, what will be state of Ellipse after
these operations?
We defined a true Mathematical expression
Only depend on the input parameters.
For same input, same output.
No mutation of state or Side effects
Also called as Pure functions.
Functional programming is programming with Pure functions.
Functional Programming
In computer science, functional programming is a
programming paradigm—a style of building the structure
and elements of computer programs—that treats
computation as the evaluation of mathematical
functions and avoids changing-state and mutable data.
- Wikipedia
Mathematical Expression
Always results into a value.
In FP, entire program can be presented as a
Mathematical expression
Well almost.
int x = 2 * 3 + 5;
Is it an expression?
= Expression
= Expression
= Statement (requires mutation)
= Statement (requires mutation)
= Expression
= Expression (mutation is avoided)
int x = a < 5 ? 5 : a;
if(a < 5) { x = 5; } else { x = a; }
val x = if(a < 5) 5 else a (scala)
for(int i=0; i<a.length;i++) b[i]= a[i] * 2;
val b = for(i <- a) yield i * 2 (scala)
Benefits of Pure functions
Context Independent
Depends only on parameters.
Highly reusable
Because they are context independent.
Can be reasoned Locally
Everything is in the function body.
Highly testable.
Can be reasoned Locally?
It's ok, for small functions
What about functions that are calling other
complex functions.
Referential Transparency & Substitution Model
Referential Transparency
If a program can be updated by replacing the function call
with result of the function call without changing its
behaviour then that function is Referentially Transparent
Function.
Example
int square(int a) { return a * a; }
int x = square(4); => x = 16;
Replacing square(4) with 16 will not change the behaviour
of the program.
So function square is Referentially transparent
Substitution Model
Substitution model is a model of reasoning a program by
substituting the referentially transparent functions with their
values.
This makes the understanding of complex program easy.
This enables the local reasoning of the functions.
And a good name for a function helps.
View of Function in FP world
What do you think when you think of a Function in
conventional languages?
We think in terms of what that function does.
In FP you think only about input and output types.
def f1: String => Int = ???
def f2: Int => Boolean = ???
def f3[A, B]: A => B = ???
Benefits of FP View
Functions become more composable.
System become more modular.
Higher order functions are possible.
They just care whether function arguments follow a
type signature.
Functional programming
Side effects
boolean hitMonster = monster.hitByShooting(gunShot);
// reduce the power of the
gunshot
boolean hitPlayer = player.hitByShooting(gunShot);
What is a side effect?
Code inside monster class
boolean hitByShooting(Gunshot gunShot) {
if(isInRange()) {
gunShot.reducePower();
return true;
}
return false;
}
<= Happening on the side
Not visible through return type.
Not Referentially Transparent function (can not be substituted)
Types of Side effects
Mutation of value.
Throwing an Exception.
I/O operations like printing or File operations.
Communicating with DB.
Remote communication.
Eliminating or delaying
the side effects
def hitByShooting(gunShot : Gunshot): (Boolean, Gunshot) = {
if(isInRange()) {
val usedGunshot = gunShot.reducePower()
(true, usedGunshot)
} else
(false, gunShot)
}
Referentially Transparent Function (can be substituted).
Visible in returned value
No more a side
effect
val (hitMonster, usedGunshot) = monster.hitByShooting(gunShot)
// reduce the power of the gunshot
val hitPlayer = player.hitByShooting(usedGunshot)
Inter-dependency is now visible in the code.
Types of pure functions make the dependency visible.
Managing IO
Printing a canvas
def draw() = {
println("-" * (width + 2))
rows.foreach { row =>
println("|" + row.map(p => p.toString).mkString + "|")
}
println("-" * (width + 2))
}
Traditional Testing with DI
def draw(ds: DisplayService) = {
ds.println("-" * (width + 2))
rows.foreach { row =>
ds.println("|" + row.map(p => p.toString).mkString + "|")
}
ds.println("-" * (width + 2))
}
Injected & mocked during tests.
Functional Implementation
def canvasAsString(): String = {
val topBorder = "-" * (width + 2) + "n"
val canvasRows = rowAsString()
val bottomBorder = "-" * (width + 2)
topBorder + canvasRows + bottomBorder
}
println(canvasAsString()) // only line in program with side effect.
Another example
Buying coffee
class Cafe {
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
cc.charge(cup.price)
cup
}
}
Clearly a side effect.
Delaying the side effect
class Cafe {
def buyCoffe(cc: CreditCard): (Coffe, Charge) = {
val cup = new Coffee()
(cup, Charge(cc, cup.price))
// charge details are returned instead of processed
}
}
Here we’ve separated the concern of creating a charge from the
processing or interpretation of that charge.
Buying multiple coffees
Buy multiple cups of coffee with a single charge on credit
card.
def buyCoffees(cc: CreditCard, n: Int) : (List[Coffee], Charge)
// call buyCoffee n times
// combine n changes into a single charge on credit card.
This was possible since Charge is now a value, and can be
processed further.
Separation of Concerns
Impure function f() of type A => B can be split into
A pure function of type A => D
where D is some description of the result of f().
Description of steps or required info to execute the
steps
An impure function of type D => B
which ack as an interpreter of these descriptions.
Executor of the steps.
Benefits of this Separation
Pure
Impure
Function
Input Output PureInput Output
Value always allow further processing
Input No or incomplete output
Denote the end of the processing chain.
Or Miss intermediate values.
Structure of Functional Code base
Pure Functional
Core
Thin outer
layer of side
effects
Exception
def failingFn(i : Int) : Int = {
val y: Int = throw new Exception("fail!");
try {
val x = 42 + 5
x + y
} catch { case e : Exception => 43 }
}
This program will fail at runtime.
Not Referentially Transparent
def failingFn(i : Int) : Int = {
// replace y with its value
try {
val x = 42 + 5
x + ((throw new Exception("fail!")): Int)
} catch { case e : Exception => 43 }
}
This program will not fail.
Exception can not be reasoned locally.
More issues with Exceptions
Exceptions are not type safe.
def map(f: String => Int) = ???
Map can not know f() can throw an exception.
This does not fit with our view of function in FP world.
Option data type
Two possible values
Some - holds some value.
None - No value exists.
def get(lookupKey: Int): String = {
for(entry <- entrySet) {
if(entry.key == lookupKey) { return entry.value }
}
throw new ValueNotFoundException() // or return null
}
Using option
def get(lookupKey: Int): Option[String] = {
for(entry <- entrySet) {
if(entry.key == lookupKey) {
Some(entry.value)
}
}
None
}
Lambda signature : Int => Option[String]
Other data type to handle Errors
Optional (Java 8)
Try (scala)
Either (scala)
Maybe (Haskell)
Internal Side effects
Consider adding element of an array
int sum(int[] intList) {
int sum = 0;
for(int i : intList) {
sum = sum + i; // mutation
}
return sum;
}
This is acceptable inside a pure function.
Eliminating Internal Side effect
Use recursion
def sum(intList: List[Int]) : Int = {
if(intList.isEmpty) 0
else intList.head + sum(intList.tail)
}
Recursion is declarative.
Tail Recursion
Stackoverflow? Use tail recursion.
def sum(intList: List[Int], total: Int): Int = {
intList match {
case Nil => total
case head :: tail => sum(tail, total + head)
// same stack frame
}
}
sum(List(1, 2, 3), 0)
Higher order functions
Consider two functions
def doubleIt(a : List[Int]) : List[Int] = {
a match { case Nil => Nil
case head :: tail => (head * 2) :: doubleIt(tail)
}}
def squareIt(a : List[Int]) : List[Int] = {
a match { case Nil => Nil
case head :: tail => (head * head) :: squareIt(tail)
}}
Example
Higher Abstraction
def processIt(a: List[Int], f: Int => Int) : List[Int] = {
a match { case Nil => Nil
case head :: tail => f(head) :: processIt(tail, f)
}}
Provides more opportunities of abstraction.
More opportunities for reuse.
Polymorphism in Types
We can do even better.
def processIt [A, B] (a: List[A], f : A => B) : List[B] = {
a match { case Nil => Nil
case head :: tail => f(head) :: processIt(tail, f)
}}
Map function
def map [A, B] (a: List[A], f : A => B) : List[B] = {
a match { case Nil => Nil
case head :: tail => f(head) :: map(tail, f)
}}
Part of standard library for FP languages.
More HOFs
Filter elements of the list.
def filter[A](x: List[A], f: A => Boolean): List[A] = ???
Similar to map but function argument result into a list
def flatMap[A, B](x: List[A], f: A => List[B]) : List[B] = ???
Fold a list into single value.
def foldLeft[A, B](x: List[A], f: (B, A) => B): B = ???
Function as First class citizen
First class Functions.
Pass function as arguments.
Return function as return types.
Declare function locally (like local variable).
Assign function to a variable.
Define function literals (also called as lambdas)
(x: Int) => x + 1
Declarative Style
Imperative Style
Write program to find even numbers, double them and sum them up.
public int calculate() {
int[] numbers = {1, 5, 10, 9, 12};
List<Integer> doubledEvenNumbers = new ArrayList<>();
for (int number : numbers)
if(number % 2 == 0)
doubledEvenNumbers.add(number * 2);
int total = 0;
for(int even : doubledEvenNumbers)
total = total + even;
return total;
}
Declarative Style
Same code in declarative style with Higher order functions
List(1, 5, 10, 9, 12)
.filter(e => e % 2 == 0)
.map(e => e * 2)
.sum
Focus on what, instead of when.
Class schedule example.
More benefits of Purity
Preserves the previous version of itself.
Persistent Data structures
Memoization
Result of expensive pure function can be cached and
reused again, this technique is called as Memoization.
// example of memoization in Groovy
def static sumFactors = { number ->
factorsOf(number).inject(0, {i, j -> i + j})
}
def static sumOfFactors = sumFactors.memoize()
Lazy evaluation
Expressions are not evaluated unless needed.
Haskell everything is evaluated lazily (as needed)
In Java and Scala streams are Lazy collections
Infinite collections can be created with lazy collection.
def fib(a: Int, b: Int): Stream[Int] =
a #:: fib(b, a + b)
val firstSeven = fib(1, 1).take(7)
firstSeven.toList // => List(1, 1, 2, 3, 5, 8, 13)
Parallel Programming
Independent pure functions can be executed in parallel.
Pure functions are inherently thread safe.
Declarative programming with language constructs help
parallel programming further.
val people : Array[People]
val (minors, adults) = people.par.partition(p => p.age > 18)
OO vs FP
FP Type hierarchy
Sub
Type1
Sub
Type2
Functions Functions Functions Functions
Every function will switch on subtypes and provide functionality
Type
OO type hierarchy
Data
Functions
Data
Functions
Data
Functions
Data
Functions
Data
Functions
Switch cases are avoided with polymorphic behaviour
Switch cases good or bad
OO programmers consider Switch cases bad.
Conditional code. Hard to maintain
Hunt down existing cases to add new cases.
Program will misbehave if you miss to update one.
FP enhanced switch cases to pattern matching and
promote them.
What’s the Truth??
Types and Operations
Type against OperationsType
Operations
Infinite Type,
Finite Operations
Finite Type,
Infinite Operations
OO Solution better
FP Solution better
Infinite Type, Finite Operations
Implemented as Polymorphism (class hierarchy).
Easy to add new Type by Subtyping.
Difficult to add new Operations.
Finite Type, Infinite Operations
FP structures called Algebraic data types (ADTs)
Easy to add new operations using Pattern matching.
Difficult to add new Types.
Algebraic data type
Composite Type
Defined by one more more data constructors.
data List a = Nil | Cons x (List xs)
This is defining a list data type with 2 constructors.
ADT Example
Representation in scala.
interface List
class Nil extends List
class Cons(head, tail) extends List
In OO terms these constructors can be mapped to
subtypes.
ADT Example
ADTs have finite number of constructors or subtypes.
For list we have two constructors or subtypes
Empty list
Non empty list with head and tail.
These constructions are exhaustive and no new
subtype will ever be added.
More ADT Examples
Option
Some | None
Either
Left | Right
Try
Success | Failure
Future
Success | Failure
OO & FP
Use ADTs and pattern matching for finite types
Use OO polymorphism for infinite types and
limited functions on those types.
Pure functions can be used in OO structure as
well.
Conclusion
Embrace immutability and Pure functions
Eliminate or delay the side effects
FP is not all or nothing
Choice is not OO or FP
FP can co-exists (nicely) with OO code
Functional in the small and OO in the large
Thank You
Questions?

More Related Content

PDF
Functional programming ii
PDF
Functional Programming Patterns (BuildStuff '14)
PDF
Thinking in Functions: Functional Programming in Python
PDF
Learning Functional Programming Without Growing a Neckbeard
PDF
An Introduction to Functional Programming - DeveloperUG - 20140311
PPT
Introduction to Functional Programming in JavaScript
PDF
Javaz. Functional design in Java 8.
PDF
46630497 fun-pointer-1
Functional programming ii
Functional Programming Patterns (BuildStuff '14)
Thinking in Functions: Functional Programming in Python
Learning Functional Programming Without Growing a Neckbeard
An Introduction to Functional Programming - DeveloperUG - 20140311
Introduction to Functional Programming in JavaScript
Javaz. Functional design in Java 8.
46630497 fun-pointer-1

What's hot (19)

PPS
Let Us Learn Lambda Using C# 3.0
PDF
Scala categorytheory
PDF
CS4200 2019 | Lecture 2 | syntax-definition
PDF
An introduction to property based testing
ODP
Clojure basics
PPTX
Functional programming
PDF
Monadic Java
PDF
Game of Life - Polyglot FP - Haskell, Scala, Unison - Part 2 - with minor cor...
PPTX
Templates presentation
PPT
Scala functions
PPTX
Functions in C++
PDF
Lazy java
PDF
Functions
PDF
Introduction to functional programming
PDF
Intro to Functional Programming
PPTX
Python programming
PPTX
PDF
Python for data science by www.dmdiploma.com
Let Us Learn Lambda Using C# 3.0
Scala categorytheory
CS4200 2019 | Lecture 2 | syntax-definition
An introduction to property based testing
Clojure basics
Functional programming
Monadic Java
Game of Life - Polyglot FP - Haskell, Scala, Unison - Part 2 - with minor cor...
Templates presentation
Scala functions
Functions in C++
Lazy java
Functions
Introduction to functional programming
Intro to Functional Programming
Python programming
Python for data science by www.dmdiploma.com
Ad

Similar to Functional programming (20)

PPTX
functions
PPT
Generalized Functors - Realizing Command Design Pattern in C++
PDF
Functions in C++
PPTX
Functions
PDF
Rethink programming: a functional approach
DOC
c.p function
PPT
Functions and pointers_unit_4
PPTX
Functional programming with FSharp
PPT
arrays.ppt
PDF
PPTX
Lecture 1_Functions in C.pptx
PDF
Functional Programming in Scala: Notes
PDF
How to start functional programming (in Scala): Day1
PPT
Lecture 4
PDF
Functionssssssssssssssssssssssssssss.pdf
PDF
Functional go
PDF
Functional Programming with Javascript
DOCX
JLK Chapter 5 – Methods and ModularityDRAFT January 2015 Edition.docx
PDF
Presentation 2 (1).pdf
DOC
1183 c-interview-questions-and-answers
functions
Generalized Functors - Realizing Command Design Pattern in C++
Functions in C++
Functions
Rethink programming: a functional approach
c.p function
Functions and pointers_unit_4
Functional programming with FSharp
arrays.ppt
Lecture 1_Functions in C.pptx
Functional Programming in Scala: Notes
How to start functional programming (in Scala): Day1
Lecture 4
Functionssssssssssssssssssssssssssss.pdf
Functional go
Functional Programming with Javascript
JLK Chapter 5 – Methods and ModularityDRAFT January 2015 Edition.docx
Presentation 2 (1).pdf
1183 c-interview-questions-and-answers
Ad

More from Prashant Kalkar (9)

PPTX
Best practices for Highly available apps on k8s.pptx
PPTX
Design principles to modularise a monolith codebase.pptx
PDF
GDCR 2022.pptx.pdf
PPTX
Exploring the flow of network traffic through kubernetes cluster.pptx
PPTX
Uncover the mysteries of infrastructure as code (iac)!
PPTX
AWS ECS workshop
PPTX
Microservices testing consumer driven contracts using pact
PPTX
Immutable infrastructure with Terraform
PPTX
Hibernate
Best practices for Highly available apps on k8s.pptx
Design principles to modularise a monolith codebase.pptx
GDCR 2022.pptx.pdf
Exploring the flow of network traffic through kubernetes cluster.pptx
Uncover the mysteries of infrastructure as code (iac)!
AWS ECS workshop
Microservices testing consumer driven contracts using pact
Immutable infrastructure with Terraform
Hibernate

Recently uploaded (20)

PPTX
Online Work Permit System for Fast Permit Processing
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PPTX
Introduction to Artificial Intelligence
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
ISO 45001 Occupational Health and Safety Management System
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
top salesforce developer skills in 2025.pdf
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
System and Network Administraation Chapter 3
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
AI in Product Development-omnex systems
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Nekopoi APK 2025 free lastest update
PDF
Understanding Forklifts - TECH EHS Solution
PPTX
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
PPTX
Transform Your Business with a Software ERP System
PPTX
CHAPTER 2 - PM Management and IT Context
Online Work Permit System for Fast Permit Processing
How to Migrate SBCGlobal Email to Yahoo Easily
Introduction to Artificial Intelligence
Upgrade and Innovation Strategies for SAP ERP Customers
ISO 45001 Occupational Health and Safety Management System
Odoo Companies in India – Driving Business Transformation.pdf
Design an Analysis of Algorithms I-SECS-1021-03
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
top salesforce developer skills in 2025.pdf
PTS Company Brochure 2025 (1).pdf.......
System and Network Administraation Chapter 3
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
2025 Textile ERP Trends: SAP, Odoo & Oracle
AI in Product Development-omnex systems
How Creative Agencies Leverage Project Management Software.pdf
Nekopoi APK 2025 free lastest update
Understanding Forklifts - TECH EHS Solution
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
Transform Your Business with a Software ERP System
CHAPTER 2 - PM Management and IT Context

Functional programming

  • 1. Functional Programming Elsevier 2016-07-26 Prashant Kalkar VTW Senior software developer
  • 2. Shortcoming of current model. What is Functional Programming (FP). Benefits of Functional Programming. Explore side effects and eliminate them. Higher order functions and lambda expressions. Collection processing in FP. Declarative Programming. Some more benefits in FP. FP vs OO and when to use them. Agenda
  • 3. Takeaways What is FP. Why to use FP. Initiate the thinking in FP. Techniques to eliminate side effects. Structure of functional code base. Structural difference between FP and OO When to use FP solution. When to use OO solution.
  • 5. Consider Example int f() { y = y + 1; return y; } What is the output of function call f()? Requires or depends on external state. Need to know the history of interactions with the system. Multiple calls will cause side effects. y = 1 // initial value Now what will be the output?
  • 6. State of Ellipse Ellipse ellipse = new Ellipse(new Rectangle(0, 0, 100, 100)); BoundingBox boundingBox = ellipse.boundingBox; boundingBox.inflate(10, 10); Mutation in object graph affect many graph objects Tracking change is difficult.
  • 7. boolean hitMonster = monster.hitByShooting(gunShot); boolean hitPlayer = player.hitByShooting(gunShot); Are these statements independent of each other? Mutation impose order.
  • 8. Solutions? Clause of issue was mutation in the programs. More precisely global mutation. Let put in some constrains on functions Only depend on the input parameters. For same input, same output. No mutation of state.
  • 9. int f(int y) { return y + 1; } Now what will be the output of functional call f(5)? Ellipse ellipse = new Ellipse(new Rectangle(0, 0, 100, 100)); BoundingBox boundingBox = ellipse.boundingBox; boundingBox.inflate(10, 10); If everything is immutable, what will be state of Ellipse after these operations?
  • 10. We defined a true Mathematical expression Only depend on the input parameters. For same input, same output. No mutation of state or Side effects Also called as Pure functions. Functional programming is programming with Pure functions.
  • 11. Functional Programming In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. - Wikipedia
  • 12. Mathematical Expression Always results into a value. In FP, entire program can be presented as a Mathematical expression Well almost.
  • 13. int x = 2 * 3 + 5; Is it an expression? = Expression = Expression = Statement (requires mutation) = Statement (requires mutation) = Expression = Expression (mutation is avoided) int x = a < 5 ? 5 : a; if(a < 5) { x = 5; } else { x = a; } val x = if(a < 5) 5 else a (scala) for(int i=0; i<a.length;i++) b[i]= a[i] * 2; val b = for(i <- a) yield i * 2 (scala)
  • 14. Benefits of Pure functions Context Independent Depends only on parameters. Highly reusable Because they are context independent. Can be reasoned Locally Everything is in the function body. Highly testable.
  • 15. Can be reasoned Locally? It's ok, for small functions What about functions that are calling other complex functions. Referential Transparency & Substitution Model
  • 16. Referential Transparency If a program can be updated by replacing the function call with result of the function call without changing its behaviour then that function is Referentially Transparent Function.
  • 17. Example int square(int a) { return a * a; } int x = square(4); => x = 16; Replacing square(4) with 16 will not change the behaviour of the program. So function square is Referentially transparent
  • 18. Substitution Model Substitution model is a model of reasoning a program by substituting the referentially transparent functions with their values. This makes the understanding of complex program easy. This enables the local reasoning of the functions. And a good name for a function helps.
  • 19. View of Function in FP world What do you think when you think of a Function in conventional languages? We think in terms of what that function does. In FP you think only about input and output types. def f1: String => Int = ??? def f2: Int => Boolean = ??? def f3[A, B]: A => B = ???
  • 20. Benefits of FP View Functions become more composable. System become more modular. Higher order functions are possible. They just care whether function arguments follow a type signature.
  • 23. boolean hitMonster = monster.hitByShooting(gunShot); // reduce the power of the gunshot boolean hitPlayer = player.hitByShooting(gunShot); What is a side effect?
  • 24. Code inside monster class boolean hitByShooting(Gunshot gunShot) { if(isInRange()) { gunShot.reducePower(); return true; } return false; } <= Happening on the side Not visible through return type. Not Referentially Transparent function (can not be substituted)
  • 25. Types of Side effects Mutation of value. Throwing an Exception. I/O operations like printing or File operations. Communicating with DB. Remote communication.
  • 27. def hitByShooting(gunShot : Gunshot): (Boolean, Gunshot) = { if(isInRange()) { val usedGunshot = gunShot.reducePower() (true, usedGunshot) } else (false, gunShot) } Referentially Transparent Function (can be substituted). Visible in returned value No more a side effect
  • 28. val (hitMonster, usedGunshot) = monster.hitByShooting(gunShot) // reduce the power of the gunshot val hitPlayer = player.hitByShooting(usedGunshot) Inter-dependency is now visible in the code. Types of pure functions make the dependency visible.
  • 29. Managing IO Printing a canvas def draw() = { println("-" * (width + 2)) rows.foreach { row => println("|" + row.map(p => p.toString).mkString + "|") } println("-" * (width + 2)) }
  • 30. Traditional Testing with DI def draw(ds: DisplayService) = { ds.println("-" * (width + 2)) rows.foreach { row => ds.println("|" + row.map(p => p.toString).mkString + "|") } ds.println("-" * (width + 2)) } Injected & mocked during tests.
  • 31. Functional Implementation def canvasAsString(): String = { val topBorder = "-" * (width + 2) + "n" val canvasRows = rowAsString() val bottomBorder = "-" * (width + 2) topBorder + canvasRows + bottomBorder } println(canvasAsString()) // only line in program with side effect.
  • 32. Another example Buying coffee class Cafe { def buyCoffee(cc: CreditCard): Coffee = { val cup = new Coffee() cc.charge(cup.price) cup } } Clearly a side effect.
  • 33. Delaying the side effect class Cafe { def buyCoffe(cc: CreditCard): (Coffe, Charge) = { val cup = new Coffee() (cup, Charge(cc, cup.price)) // charge details are returned instead of processed } } Here we’ve separated the concern of creating a charge from the processing or interpretation of that charge.
  • 34. Buying multiple coffees Buy multiple cups of coffee with a single charge on credit card. def buyCoffees(cc: CreditCard, n: Int) : (List[Coffee], Charge) // call buyCoffee n times // combine n changes into a single charge on credit card. This was possible since Charge is now a value, and can be processed further.
  • 35. Separation of Concerns Impure function f() of type A => B can be split into A pure function of type A => D where D is some description of the result of f(). Description of steps or required info to execute the steps An impure function of type D => B which ack as an interpreter of these descriptions. Executor of the steps.
  • 36. Benefits of this Separation Pure Impure Function Input Output PureInput Output Value always allow further processing Input No or incomplete output Denote the end of the processing chain. Or Miss intermediate values.
  • 37. Structure of Functional Code base Pure Functional Core Thin outer layer of side effects
  • 38. Exception def failingFn(i : Int) : Int = { val y: Int = throw new Exception("fail!"); try { val x = 42 + 5 x + y } catch { case e : Exception => 43 } } This program will fail at runtime.
  • 39. Not Referentially Transparent def failingFn(i : Int) : Int = { // replace y with its value try { val x = 42 + 5 x + ((throw new Exception("fail!")): Int) } catch { case e : Exception => 43 } } This program will not fail. Exception can not be reasoned locally.
  • 40. More issues with Exceptions Exceptions are not type safe. def map(f: String => Int) = ??? Map can not know f() can throw an exception. This does not fit with our view of function in FP world.
  • 41. Option data type Two possible values Some - holds some value. None - No value exists. def get(lookupKey: Int): String = { for(entry <- entrySet) { if(entry.key == lookupKey) { return entry.value } } throw new ValueNotFoundException() // or return null }
  • 42. Using option def get(lookupKey: Int): Option[String] = { for(entry <- entrySet) { if(entry.key == lookupKey) { Some(entry.value) } } None } Lambda signature : Int => Option[String]
  • 43. Other data type to handle Errors Optional (Java 8) Try (scala) Either (scala) Maybe (Haskell)
  • 44. Internal Side effects Consider adding element of an array int sum(int[] intList) { int sum = 0; for(int i : intList) { sum = sum + i; // mutation } return sum; } This is acceptable inside a pure function.
  • 45. Eliminating Internal Side effect Use recursion def sum(intList: List[Int]) : Int = { if(intList.isEmpty) 0 else intList.head + sum(intList.tail) } Recursion is declarative.
  • 46. Tail Recursion Stackoverflow? Use tail recursion. def sum(intList: List[Int], total: Int): Int = { intList match { case Nil => total case head :: tail => sum(tail, total + head) // same stack frame } } sum(List(1, 2, 3), 0)
  • 48. Consider two functions def doubleIt(a : List[Int]) : List[Int] = { a match { case Nil => Nil case head :: tail => (head * 2) :: doubleIt(tail) }} def squareIt(a : List[Int]) : List[Int] = { a match { case Nil => Nil case head :: tail => (head * head) :: squareIt(tail) }} Example
  • 49. Higher Abstraction def processIt(a: List[Int], f: Int => Int) : List[Int] = { a match { case Nil => Nil case head :: tail => f(head) :: processIt(tail, f) }} Provides more opportunities of abstraction. More opportunities for reuse.
  • 50. Polymorphism in Types We can do even better. def processIt [A, B] (a: List[A], f : A => B) : List[B] = { a match { case Nil => Nil case head :: tail => f(head) :: processIt(tail, f) }}
  • 51. Map function def map [A, B] (a: List[A], f : A => B) : List[B] = { a match { case Nil => Nil case head :: tail => f(head) :: map(tail, f) }} Part of standard library for FP languages.
  • 52. More HOFs Filter elements of the list. def filter[A](x: List[A], f: A => Boolean): List[A] = ??? Similar to map but function argument result into a list def flatMap[A, B](x: List[A], f: A => List[B]) : List[B] = ??? Fold a list into single value. def foldLeft[A, B](x: List[A], f: (B, A) => B): B = ???
  • 53. Function as First class citizen First class Functions. Pass function as arguments. Return function as return types. Declare function locally (like local variable). Assign function to a variable. Define function literals (also called as lambdas) (x: Int) => x + 1
  • 55. Imperative Style Write program to find even numbers, double them and sum them up. public int calculate() { int[] numbers = {1, 5, 10, 9, 12}; List<Integer> doubledEvenNumbers = new ArrayList<>(); for (int number : numbers) if(number % 2 == 0) doubledEvenNumbers.add(number * 2); int total = 0; for(int even : doubledEvenNumbers) total = total + even; return total; }
  • 56. Declarative Style Same code in declarative style with Higher order functions List(1, 5, 10, 9, 12) .filter(e => e % 2 == 0) .map(e => e * 2) .sum Focus on what, instead of when. Class schedule example.
  • 58. Preserves the previous version of itself. Persistent Data structures
  • 59. Memoization Result of expensive pure function can be cached and reused again, this technique is called as Memoization. // example of memoization in Groovy def static sumFactors = { number -> factorsOf(number).inject(0, {i, j -> i + j}) } def static sumOfFactors = sumFactors.memoize()
  • 60. Lazy evaluation Expressions are not evaluated unless needed. Haskell everything is evaluated lazily (as needed) In Java and Scala streams are Lazy collections Infinite collections can be created with lazy collection. def fib(a: Int, b: Int): Stream[Int] = a #:: fib(b, a + b) val firstSeven = fib(1, 1).take(7) firstSeven.toList // => List(1, 1, 2, 3, 5, 8, 13)
  • 61. Parallel Programming Independent pure functions can be executed in parallel. Pure functions are inherently thread safe. Declarative programming with language constructs help parallel programming further. val people : Array[People] val (minors, adults) = people.par.partition(p => p.age > 18)
  • 63. FP Type hierarchy Sub Type1 Sub Type2 Functions Functions Functions Functions Every function will switch on subtypes and provide functionality Type
  • 65. Switch cases good or bad OO programmers consider Switch cases bad. Conditional code. Hard to maintain Hunt down existing cases to add new cases. Program will misbehave if you miss to update one. FP enhanced switch cases to pattern matching and promote them. What’s the Truth??
  • 66. Types and Operations Type against OperationsType Operations Infinite Type, Finite Operations Finite Type, Infinite Operations OO Solution better FP Solution better
  • 67. Infinite Type, Finite Operations Implemented as Polymorphism (class hierarchy). Easy to add new Type by Subtyping. Difficult to add new Operations. Finite Type, Infinite Operations FP structures called Algebraic data types (ADTs) Easy to add new operations using Pattern matching. Difficult to add new Types.
  • 68. Algebraic data type Composite Type Defined by one more more data constructors. data List a = Nil | Cons x (List xs) This is defining a list data type with 2 constructors.
  • 69. ADT Example Representation in scala. interface List class Nil extends List class Cons(head, tail) extends List In OO terms these constructors can be mapped to subtypes.
  • 70. ADT Example ADTs have finite number of constructors or subtypes. For list we have two constructors or subtypes Empty list Non empty list with head and tail. These constructions are exhaustive and no new subtype will ever be added.
  • 71. More ADT Examples Option Some | None Either Left | Right Try Success | Failure Future Success | Failure
  • 72. OO & FP Use ADTs and pattern matching for finite types Use OO polymorphism for infinite types and limited functions on those types. Pure functions can be used in OO structure as well.
  • 73. Conclusion Embrace immutability and Pure functions Eliminate or delay the side effects FP is not all or nothing Choice is not OO or FP FP can co-exists (nicely) with OO code Functional in the small and OO in the large