1. A brief introduction/summarization about functional
programming (FP) and paradigm shift of software
engineering from OOP to FP for Java developers
Thang Ngoc Mai
Introduction to
Functional Programming
KMS Technology
2. 2
OOP has served us well but it has drawbacks
☐ Hard to Achieve Concurrency
Imperative paradigm does not fit very well with concurrency
need as it is based on changing state and ordered steps.
It is also hard to avoid the evil shared mutability in OOP code.
As of now, multithread programming, requiring synchronized
access, is the assembly language of concurrency.
☐ Less Re-Usable Abstractions
OOP model is hardly usable widely because every
object model is so unique for each
situation/problem. This makes modularity of OOP
less attractive
Also it is hard to do it right in OOP design because
there can be so many candidate models to solve a
same problem. And even in case we can make it
right, later we still might have to throw them away
when business change. And still we can hardly re-
use them in other contexts.
How many times you have developed the
Employee/Customer classes in your career?
It is time to look out for better alternatives.
☐ Imperative
Intent of program can be hard to
understand with imperative code
because the code is more about how
and not about what.
3. 3
Why FP?
☐ Declarative
Focus on results, not steps
Result in expressive yet concise code.
And thus intent of code is easier to
understand
☐ Concurrency
This is the notable reason why FP gains
widespread interest recently.
Functions are pure (no side effect) thus
are always safe for concurrency. In
context where mutating state is not
avoidable, Actor model and Software
transactional memory (STM) come to
rescue.
☐ Coarse-grained Abstractions
FP abstract more details from developers such as
iteration/caching/concurrency/lazy evaluation.
These mundane details are handled by languages and
runtimes, giving developers more time to solve real
problems.
The more low-level details a programming language
can handle for you, the fewer places that leave you to
introduce bugs and complexity.
☐ Code Reuse via Composition
FP makes code understandable by
minimizing moving parts (changes)
A function should be side effect free thus
has no dependencies and therefore easier
to reuse (better modularity).
4. 4
We Should Have FP in Our Toolbox
☐ Side Effects
The biggest advantage of FP and also the biggest
disadvantage of FP is side effect since we do need
side effect in software (etc. IO)
☐ No Panacea
Both OOP and FP are tools, not panaceas. Each
has advantages and disadvantages. Let’s have a
bigger toolbox and a broadened perspective.
5. 5
So What is FP?
☐ FP is More a Mindset
FP is more a mindset than languages or tools. You can even code functionally in Java
although syntax will be cumbersome. First point is when developers think functionally,
they should focus on results instead steps to solve a problem.
Secondly, because FP represents problems differently with different building blocks,
developers have to adapt with these building blocks and how to glue them together.
Thus FP requires developers to think in a different way that they do in OOP
☐ Programming with Functions
Functional program is just a function. Thus functional applications or features are composed by
small functions together.
In OOP, the units of reuse are classes thus it encourages developers to create unique data
structures. In contrast, function is the building block in FP. And thus, FP instead prefers a few key
data structures (list, set, map) with highly optimized operations on those data structures. These
differences are subtle but powerful since it simplify and enable better code reuse mechanism.
“Functional programming is a programming
paradigm that treats computation as the
evaluation of mathematical functions and
avoids state and mutable data”
6. 6
Concepts in FP
From here I will briefly introduce each common concept in functional programming. Below is list of them.
Higher Order Function
First Class Function
Currying
Partial Application
Memoization
Lazy Evaluation
Common Transformations in FP: filter, map, and reduce
Dispatch in FP
Recursive Looping
Monad
7. 7
Higher Order Function
Higher order functions are functions which can either take other functions as arguments or return them as results.
☐ Groovy Example
def makeCounter() {
def very_local_variable = 0
return { return very_local_variable += 1 }
}
c1 = makeCounter()
c1()
c1()
c1()
c2 = makeCounter()
makeCounter() is a not a normal function. It
is a higher order function which returns a
another function (actually a closure here)
which later will be assigned to c1 and c2
variables. Note that in Groovy, anything
inside curly braces is a code block.Invoke c1() three times and receive
1,2,3 respectively.
Invoke makeCounter() again to obtain
a new counter function which starts at
1
8. 8
First Class Function
Functional languages treat function as first class citizen
With above definition, you can easily see that function is not (yet) a first class citizen in Java. At least until Java 8 is
released early next year with support for Lambda Expressions.
☐ What is First Class Citizen??
☐ What Does All that Mean?
First class function allows uses of functions in unexpected
ways and force thinking about solutions differently. In OOP,
we think about classes and how they are structured and
interact with each other. In FP, we think about functions
and how to create them (even at runtime) and compose
them together.
In any language, a first class citizen is an entity that can
be:
Stored in variables and data structures
Constructed at run-time
Passed as a parameter
Returned from a subroutine
Assigned into a variable
9. 9
Currying Currying is a technique of transforming a
function that takes multiple arguments in such
a way that it can be called as a chain of
functions, each with a single argument.
☐ How Does It look?
Given , currying produces:
.
☐ JRuby Examples
product = ->(x,y,z){x * y * z}
product.(2,4,6)
product.curry[2][4][6]
We create a lambda here (assigned to product) which
take three parameters and multiple them together and
return result
product can be invoked either in a
normal way or in a curried way like
this to produce a same result of 48
product = ->(x,y){x * y}
double = product.curry[2]
quadrate = product.curry[4]
octate = product.curry[8]
Again, create a lambda
But this time, we use currying to create
three different functions based on original
one. This demonstrates idea about currying
acts as a factory for functions
10. 10
Partial Application
☐ Definition
Partial application (or partial function application) refers to the process of fixing a number of
arguments to a function, producing another function of smaller arity.
Note that partial application is different with currying but these two terms are often used
interchangeably
☐ JRuby Example
binary_operator = ->(operator, x, y){operator[x,y]}
adder = ->(x,y){x + y}
product = ->(x,y){x * y}
# Use curry() for partial application
curried_product = binary_operator.curry[product]
curried_adder = binary_operator.curry[adder]
# Note Ruby’s beautiful syntax
curried_product1 = binary_operator.curry[:*]
curried_adder1 = binary_operator.curry[:+]
# returns 30
curried_product.(5,6)
# returns 11
curried_adder.(5,6)
binary_operator is a higher order
function which take a binary function
and apply it to the other parameters.
We have two binary operators
adder and product.
We use curry in JRuby to partially
apply adder and product to
binary_operator function and yielding
two functions.
11. 11
Partial Application
☐ Another Example
composer = ->(f,g,x){f.(g.(x))}
product = ->(x,y){x * y}
double = product.curry[2]
quadrate = product.curry[4]
octate = composer.curry[double, quadrate]
# Returns 800
octate.(100)
We define a function to combine
functions together.
Then use partial application to yield a new
function from two original ones.
12. 12
OOP Design Patterns in FP
Neal Ford has three articles on this topic. According to those, in the functional-programming world, traditional design
patterns generally manifest in one of three ways:
The pattern is absorbed by the language.
The pattern solution still exists in the functional paradigm, but the implementation details differ.
The solution is implemented using capabilities other languages or paradigms lack. (For example, many solutions
that use metaprogramming are clean and elegant — and they're not possible in Java.)
I just try to summarize his articles here into a few points below.
Command pattern is no longer needed in FP
Currying is used as Function Factory and it is supported at language level
With first class function, Template Method and Strategy, Adapter become much simpler
With presence of memorization (Groovy and Clojure), FlyWeight is not necessary any more. This is an example of
offloading mundane tasks to language and runtimes
Operator overloading and meta-programming makes Interpreter become much simpler and more powerful
Language level feature like Pattern matching in Scala make Visitor pattern cumbersome and almost no longer
needed (Martin et al. chapter 15).
13. 13
Caching and Memoization
In OOP languages, caching generally happen at object level and developers mush manage it themselves. Many functional
programming languages build caching in function level via memorization. This is also an example of how FP strives to
minimize moving parts by building reusable mechanism into the runtime. Again the idea is all about buying more time for
developers to focus on their own tasks. Memorization is all about asking runtime to perform caching at function level
(Note that a non-pure function should not be cached as it is a source of bugs). Let’s take a look at a sample API for
memorization from Groovy to see how handy they are.
memoizeAtMost(max) call which caches a maximum number of invocations
memoizeAtLeast(min) call which keeps at least a certain number of invocation results
and memoizeBetween(min, max) which keeps a range results (between a minimum and a maximum)
def plus = { a, b -> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
// other forms:
//at least 10 invocations cached
def plusAtLeast = { ... }.memoizeAtLeast(10)
// at most 10 invocations cached
def plusAtMost = { ... }.memoizeAtMost(10)
// between 10 and 20 invocations cached
def plusAtLeast = { ... }.memoizeBetween(10, 20)
14. 14
Lazy Evaluation
☐ What is It?
Lazy evaluation is deferral of expression
evaluation for as long as possible
It is a feature of many functional
programming languages
☐ Why Lazy Evaluation matter?
Defer expensive calculation until they are
absolutely needed
Can create infinite collections which is not
possible with eager collections
Reduced storage size as we don’t have to store
everything upfront
Allow to generate more efficient code
15. 15
Common Transformations
Object-oriented languages encourage us to create class-specific methods, and you can capture recurring patterns for later reuse. Functional
languages help us to achieve reuse by encouraging the application of common transformations to data structures, with higher-order functions to
customize the operation for specific instances. Below are common transformations in FP which have different names in different languages. Note
that there are inconsistencies of terminology for same transformation in different languages. Here I summarize some common transformations
which are well noted in article #16 in Neal Ford’s functional thinking series.
☐ map and collect
A transformation which invokes a function on each
element from a list then creates a new list containing
values return by that function
☐ filter & findAll &select
A transformation which invokes an input predicate on
each element from a list to determine which values will
be included in the return list.
A predicate is a function which only returns true or
false.
☐ Reduce & inject & reduceLeft
Combine all elements by applying a specified binary
operation
18. 18
Reduce & inject & reduceLeft
# Returns result: 55
(1..10).reduce(:+)
def list = 1..10
// return result: 55
list.inject {x,y -> x + y}
☐ JRuby ☐ Groovy
val list = 1 until 11
//Return result: 55
list.reduceLeft((a,b) => a + b)
; Returns result: 55
(reduce + (range 1 11))
☐ Clojure
☐ Scala
19. 19
pmap in Clojure
As we are familiar with map already in previous page, let's examine pmap (paralel) in Clojure which will execute mappings
concurrently (and also semi-lazily). Presence of building block such as pmap demonstrates idea (yes, again) how language
and runtimes can handle mundane tasks for developers so that we will have more time to focus on resolving real
problems.
I left out implementation of fetch-url since it is not needed to demonstrate the idea. Let’s suppose we already had fetch-
url function implemented somewhere. The code in this example executes fetching content from each website in parallel.
If you are already familiar with Execution Framework in Java (I assume you are) then you can see that how cumbersome it
is the equivalent code in Java to do the same thing here with all Callable, Future, Executor, ExecutorService along the way.
Let language and runtimes do these things for us. Here I want to mention a quote from Dean Wampler:
“Multithreaded programming, requiring synchronized access to shared, mutable state, is
the assembly language of concurrency”
; Having a list of url to fetch
(def url-list (list "www.url1.com" "www.url2.com" "www.url3.com"))
; Returns
(pmap #(fetch-url %) url-list)
☐ pmap Contrived Simple Stupid Example
20. 20
Parallel Collections in Scala
Thanks to Nhan Tran who gave me an example about parallel collections in Scala which is similar to the pmap example
above in Clojure but with different approach. Instead of concurrent function, concurrency is built inside parallel
collections like ParArray, ParVector, ParHashMap etc. Let’s take a look at an example.
Above example is from scala’s documentation on parallel collections in following link.
http://docs.scala-lang.org/overviews/parallel-collections/overview.html
// Create a list
val list = (1 to 10000).toList
// Convert it to a parallel list with par() then call map to transform to
// a new list by adding 42 to each element concurrently.
list.par.map(_ + 42)
21. 21
Dispatch in FP
Working on Java, we depend on if and switch statements for dispatch. FP provides us some alternatives for the same
purpose. Groovy offers a switch statement which accepts dynamic types while Scala’s flavor is pattern matching. And
Clojure has multi methods – a functional polymorphism which is equivalent to polymorphism in OOP with fewer
limitations. Let’s take a look.
☐ Multi Methods Example
(defmulti auto-answer (fn [caller] (caller :is-a)))
(defmethod auto-answer :girl [caller] "I love you")
(defmethod auto-answer :friend [caller] "What's up")
(defmethod auto-answer :colleague [caller] "How are you")
(defmethod auto-answer :boss [caller] "Yes sir, sure")
(defmethod auto-answer :default [caller] "mmm")
=> (auto-answer {:is-a :friend})
"What's up"
=> (auto-answer {:is-a :colleague})
"How are you"
=> (auto-answer {:is-a :girl})
"I Love You"
In Clojure, a dispatch function is
defined by defmuti. Any
invocation of auto-answer will
pass parameters to this function.
Based on value retuned by
dispatch function, execution will
be dispatched to appropriate
method. This is similar with
behavior we have in OOP’s
polymorphism
All these new dispatch mechanisms are
powerful and we don’t need to depend on
design patterns like Factory but they
requires a change in the way we think as it
is part of thinking functionally
22. 22
Recursive Looping
At this point, you might not be surprised any more to know that functional approach does not favor use of
constructs like ‘for’ and ‘while’ for looping and iteration. Instead, Looping and iteration are replaced /
implemented by recursive function calls (Rich Hickey)
☐ What Languages Support Tail Recursion?
Clojure has ‘recur’ and 'trampoline’ as special operators to support tail call optimization
(TCO).
Scala support tail call optimization at language level.
Groovy does not (yet) support TCO. However it has trampoline.
JRuby does not support TCO yet.
Tail call and tail recursion is a subproject to introduce TCO for the JVM and Hopefully JDK 1.8
will come with TCO support. That would enable TCO for all languages on the JVM.
☐ So What about Stack Space Problem?
Recursion is nice but it has a problem with stack space consumption. Recursive function can easily
result in a stack overflow exception with large enough recursive calls.
Many languages guarantee that function calls made in tail position do not consume stack space and
thus recursive loops utilize constant space. Note: Same optimization cannot be achieved with head
recursion.
With such tail recursion optimization, we have peace in mind when writing recursive function.
23. 23
Monad
Probably Monad is the most difficult to understand concept in functional programming. It could take you 3 days or
probably months to understand. However, the good news is you don’t need to understand Monad to apply FP in your
daily assignments. Once you get used to functional programming, I believe soon you will understand Monad. I would
recommend following articles for getting started:
Understanding monads
http://en.wikibooks.org/w/index.php?title=Haskell/Understanding_monads&oldid=933545
Don’t fear monads
http://channel9.msdn.com/Shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads
In case you need more articles, here is a consolidated list of all tutorials about monads
http://www.haskell.org/haskellwiki/Monad_tutorials_timeline
24. 24
FP is On The Rise
☐ Results over Steps
Java eased our interaction with memory
management; functional programming languages
eased our focus on how steps should be done.
Examples are details on concurrency, iteration,
transformations and caching can be handled by
languages and runtime.
The more low-level details a programming language
can handle for you, the fewer places that leave you
to introduce bugs and complexity
☐ Think Functionally
FP offers new and powerful tools which can help solve tricky problems in
elegant ways. Developers need to adapt to functional thinking to make use
of them effectively.
So start thinking about resolving problem with how, wrapping function in
list/tree/hash, manipulating array and tree with functions and so on.
☐ Minimize Moving Parts
OOP makes code understandable by
encapsulating moving parts. FP makes code
more understandable by minimizing
moving parts. Immutability is one primary
reason why FP shines in concurrency.
25. 25
Recommendation on Where to Start
1. If you are a Java developer and you are new to FP then first go through 20 articles from Neal Ford in his functional
thinking series. These series of articles would have convinced you on how elegant and powerful FP is. I like Neal
Ford’s series because it discuss in detail on how FP can help us (developers) to work more efficiently. The series is
also very readable.
2. Then, you might want to start with the book “Functional Java Programming for Java Developers” to have a fair grip
on Data structures / Algorithm / Concurrency in FP.
3. You then can start to learn and use a functional language seriously like Scala or Groovy or Clojure. I was started
with Clojure (and Clojure is my favorite) but I would recommend Scala or Groovy as I think getting familiar to
Clojure syntax could distract your focus on FP concepts.
4. From that point, you might want to tackle the most difficult topic in FP: Monad. Notes: You should not start to
learn FP with Monads. That would slow your learning process.
26. 26
References
1. Functional Thinking 20 articles series – Neal Ford - http://www.ibm.com/developerworks/java/library/j-
ft1/index.html
2. Dean Wampler 2011. Functional Java Programming for Java Developers
3. Why Functional Programming Matters - http://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf
4. Object Oriented Programming Oversold - http://www.geocities.com/tablizer/oopbad.htm
5. Martin, F., 2010. Domain Specific Languages. Addison Wesley
6. Venkat, S., 2011. Programming Concurrency on the JVM
7. Functional Programming - http://en.wikipedia.org/wiki/Functional_programming
8. Don’t fear monads: http://channel9.msdn.com/Shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads
9. State of Lambda: Libraries Edition: http://cr.openjdk.java.net/~briangoetz/lambda/collections-overview.html
10.Martin at el. 2011. Programming in Scala 2nd edition. Artima Inc;