The Need for… Functional Programming

Functional programming

A Hardware Issue Became a Software Problem

During the last decades we are all witnesses of computer systems constantly improving in speed, efficiency, increasing space for storing data and decreasing the size of the components. The popular Moore’s law was a correct prediction that the number of transistors of the largest microprocessors will double about every two years, since 1970s. But increasing the number of transistors on a chip and increasing processor’s frequency, among other things, also requires exponentially more power.

Processors were originally developed with only one core. Around 2005, in order to continue delivering regular performance improvements for general-purpose processors, manufacturers such as Intel and AMD have turned to multi-core designs, sacrificing lower manufacturing-costs for higher performance in some applications and systems. (source Wikipedia)

Traditionally, computer software has been written for serial computation. To solve a problem, an algorithm is constructed and implemented as a serial stream of instructions, executed one at a time. In order to use the resources of a multi-core processor, some kind of parallel or concurrent execution approach became a need. Suddenly, due to the change applied by hardware manufacturers, software developers must rethink the design of their programs.

no_of_coresData from Kunle Olukotun, Lance Hammond, Herb Sutter, Burton Smith, Chris Batten and Krste Asanovic

To make all a bit more complex for software developers, it is expected that Moore’s law prediction will remain in the following years as well. It will be achieved by constant increase of the number of cores a processor will have and not by increasing processor frequency.

Parallel and Concurrent Programming are Hard

Parallel and concurrent programming approaches are in essence different. Parallel programming means executing programs faster on parallel hardware, while concurrent programming means explicitly managing concurrent execution threads. But, one thing they have in common – both are very hard to implement and maintain!

The problem with concurrent approach is the non-determinism, caused by concurrent threads accessing shared mutable state. In order to get deterministic processing, we should avoid the mutable state. Avoiding mutable state means programming functionally. Function should, by definition, using the same set of input parameters to always return the same result. Using this characteristics of a functions, they can be easily run in parallel and thus are a better alternative for multi-core processor systems.

Functional Programming

Functional programming is one of the programming paradigms. It is for many decades popular in academia and used for scientific purposes. In the last 10 years it becomes more and more practiced within commercial IT companies, too. Most probably you’ve lately heard about programming languages like Scala, F#, Closure etc. which all have a functional programming features. Reactive programming, using building blocks of functional programming, is in hype, too.

Functional programming is considered a part of declarative programming paradigm. Contrary to imperative style of programming, where the code represents how to do something, in declarative programming style one writes what  needs to be done, without necessary specifying details ‘how’ it should be done. Functional programming gives a higher level of abstraction, better code re-usability, less code duplication (DRY, don’t-repeat-yourself principle), lazy evaluations, easier implementation of parallelism etc. Although not all modern programming languages are functional in nature, they offer the possibilities to write code in a declarative manner. But in order to switch from imperative to declarative programming style, one needs to change the way of thinking and approaching programming solutions. It’s not just a change in languages’ syntax but the change needs to be applied to the semantic (how the problems are being approached and solved).

The adoption of functional programming within the development teams is not going that easy. The reasons for that most probably lays to the fact that functional programming is, in general, more complex than traditional structural programming. It has a higher level of abstraction. But, another important aspect is that, most of us who are programmers today, are only thought to think and implement algorithms in a structural/imperative way. This is the case for Serbia but I’m sure it is similar on a global level, too. When you practice something for years, it becomes a habit and habits are difficult to change.

Changing the Perspective

On the other side, it should not be that hard to switch the perspective and write programs in a declarative manner. SQL database statements, which we are all using since the start of our careers, are in fact represented by a declarative statements. Take next simple example:

SELECT e.name
  FROM employees e JOIN positions p ON e.positon_id = p.id
 WHERE p.name = 'SENIOR'
   AND e.age > 40;

We are telling the database to give us all data of employees having a relation to position which name is SENIOR and are older than 40. Quite easy and straightforward.

Note that we are NOT telling our database to:

  • open employees table
  • for each record in employees table do next:
    • open positions table and traverse through its records and try to match id column with employees.position_id column values
    • if there is an index defined on a column positions.id use it to have better performances
    • if there is a match, store those matched records from employees and positions table in a set for return
    • if positions.id column has unique values, continue with the next record from employees table;
      else – continue to look for a matched records in remaining records in positions table
  • filter matched records and keep only those where positions.name = ‘SENIOR’ and age greater than 40
  • continue with the next record in employees table
  • when all records are checked, return employees.name for found records.

… or something like this.

Our database is smart enough to figure this out on its own and decide how to find and return us what we requested from it (by our SQL statement), in an efficient way.

Java 8 Example

To illustrate similar difference of imperative vs. functional (declarative) programming, here is an example in the latest Java 8 version (but this time in reverse order).

The usual approach, in the previous versions of Java, is an imperative solution:

public Set<Employee> findSeniors(Set<Employee> employees) {
    Set<Employee> result = new HashSet<>();
    for (Employee e : employees) {
        if (e.getPostion().equals(Postion.SENIOR)
                && e.getAge() > 40) {
            result.add(e);
        }
    }
    return result;
}

Using new Java 8 features, Lambda expressions, method references and Stream API, we are able to express our application code in the declarative way:

public Set<Employee> findSeniors(Set<Employee> employees) {
    return employees.stream()
        .filter(e -> e.getPosition().equals(Postion.SENIOR))
        .filter(e -> e.getAge() > 40)
        .map(Employee::getName)
        .collect(toSet());
}

The code is much less verbose, easier to read and understand and even possible to execute using multiple parallel threads.

Conclusion

By the evolution of programming languages in the recent years, we are having the possibility to express our application code in a declarative manner. The compiler and/or underlying language virtual machine will decide how to execute it. The parallel programming still remains not easy. Nevertheless, programming language designers are keeping figuring out better and more efficient ways to utilize multi-core systems. But in order for this to become reality in practice, we, as software developers, should stop from “micromanaging” everything in our code – telling it how to do something. Instead, we should focus on what our program has to do. Of course, it’s easier said than done, but we need to start taking the functional approach into consideration.

Note: This blog post is published at IT Konekt blog, which is the biggest online IT event in region.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.