Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Exploring the Real Power of Functional Programming

DZone's Guide to

Exploring the Real Power of Functional Programming

Some think higher order functions are the main benefit of FP, but let's explore the benefits of lazy evaluation and functional composition with Scala.

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

We have been programming with object-oriented technology for quite a while. But now we are moving away from it.

Functional Programming is getting a lot of attention nowadays. Most mainstream languages now support functional elements, i.e Java, C++, C#, etc. Basically, it is one of the paradigms of writing code where we write less code and do more.

Why Do We Really Care About It?

Around 2003, when people realized that single-core processors weren't enough, manufacturers started developing multi-core processors. Writing multi-threaded application was really hard. On a single processor, multi-threaded applications are more like multi-tasking.

But in a multi-threaded, multi-core system, things are quite different. An application that may be broken already might pretend to work correctly on a single core, but on a multi-core processor, it ends up being broken.

One of the reasons is that on the multi-core system, threads are on steroids. They are running continuously, so they can access more data much more rapidly. As a result, it has become problematic to write programs correctly and to make those programs run concurrently. So it has become a huge problem for us as we develop applications. Another problem arises from having mutable states. It is extremely difficult to work with mutability, especially when multiple threads start sharing it.

And more mutability means more error-prone code. Whereas functional programming is inherently thread-safe.

What Is Wrong With Mutability?

  1. Hard to reason
  2. Hard to make concurrent
  3. Hard to parallelize

Functional programming prefers the declarative style of coding over imperative style. Declarative programming is less verbose and focuses on assignment less programming and using pure functions.

What Is a Pure Function?

A pure function gives exactly the same result no matter how many times you ask as long as your input and output are exactly the same.

For example, We will see the same code in both styles of coding:

def factorial(n: Int): Int = {
    var result = 1
    var i = 1
    while (i <= n) {
        result = result * i
        i = i + 1
    }
    result
}

def factorial(num:Int): Int = {
    if(num == 1) num
    else
    num * factorial(num - 1)
}


If we look at the two approaches to solving the same factorial problem, the first approach is using the imperative style of coding, where there is lots of mutation, it's too verbose, and we have to say what to do and how to do it at every step.

But the second approach is the declarative style of coding, which is assignment-less, concise, more expressive, thread-safe, has less explicit mutation, and we are not telling the code what to do at every step.

When we talk or hear about functional programming, people usually think that immutability and higher-order functions are extremely important. But the really charming features of functional programming are:

  1. Functional composition
  2. Lazy evaluation

Functional composition makes code more expressive, concise, and easier to understand.

For example, find all even numbers greater than 5 and double their value:

scala> val list = (1 to 10).toList
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> list.filter(_ > 5).filter(_ % 2 == 0).map(_ *2)
res20: List[Int] = List(12, 16, 20)


The code is very expressive, it is easy to understand what is happening at every step, it is highly cohesive, and there is no explicit mutation.

But one thing to notice: It creates lots of intermediate collections while computing the final result. To avoid unnecessary computations, lazy evaluation adds efficiency to your code.

Laziness leads to efficiency in code. Now, we are not making copies and copies of the object. You can defer execution until a much later time. That’s one of the biggest benefits you get out of this.

For example,

scala> list.view.filter(_ > 5).filter(_ % 2 == 0).map(_ *2).toList
res22: List[Int] = List(12, 16, 20)


Now, it will be evaluated lazily. It will never create intermediate collections. It will start evaluating it when we actually need the result. In our case, when we do .toList, it starts executing it. So, it never wastes performance. It is very hard for code to be efficient without laziness.

So, the biggest benefit of functional programming is that you get code clarity. You don’t need to waste time to figure out what is happening at every step. There is no mutation, and you can easily make it concurrent. When functional compositions meet with lazy evaluation, that is where reactive programming starts.

The main aim of this blog is to understand the essence of functional programming. I have used Scala for these examples. In our next blog, we will go deeper to understand lazy evaluation.

Please feel free to make suggestions or comments!

References

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
scala ,function composition ,functional programing ,lazy evaluation ,java ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}