Declarative Programming in Java 8

Java is an object oriented language that treats objects as first class citizens. Objects are the basic tools for building applications in Java. Ten years ago, OOP was a religion, now it is just a tool, and we should be able to add more tools to our toolset, because it is not a religion anymore! Declarative programming is one of these powerful tools that we can add to our toolset to construct efficient, less verbose, and concurrent friendly code.
It’s often hard to tell whether a language is fully functional or not, however, it’s more possible to tell to what extent a language supports functional paradigms. Is it possible to store a reference to a function? Is it possible to pass functions as parameters? Is it possible for a function to return another function? The answer is NO because functions were always considered as second class citizens in Java.
Surprisingly, Javascript which was initially developed to validate web forms does support these functional paradigms.

//store a reference to a function in a variable
var zero = function(){
  return 0;
};
// passing functions as parameters
function fn(callback){ // callback is a function
callback(); //calling callback
}
// a function that returns a function
var v = function(){
  var inner = function(){
  return 1;
  };
  return inner;
}

Fortunately, these features have been added to Java 8. Finally, Java supports lambda expressions and method references.

Method references

static int fn(){  
        return -1;
}
Supplier<Integer> supplier = Main::fn;
System.out.println(supplier.get());

supplier is just a variable that holds a reference to a function that returns an integer. fn will only get executed when the get() function get called.

System.out.println(supplier.get()); // the actual execution of fn

This helps a lot in writing lazy code. Assume that we have these two functions, the first is expensive and the other is not and the second function relies on a value provided by the expensive one.

int fn(){
System.out.println("Bloody Expensive!!");
return 0;
}
int gn(int a, int b){
 if(a<10){
  return a;
 }else{
  return a + b;
 }
}

// calling gn using fn result
System.out.println(gn(4,fn()));

Quite simple I suppose, fn will always be called although it’s only required if the value of a is less than 10.We often count our chicken before they hatch.
So lets fix that by being more lazy, instead of passing the raw value of an integer, we can pass a function that provides an integer.


int gn(int a, Supplier<Integer> supplier){
 if(a<10){
  return a;
 }else{
  return a + supplier.get();
 }
}

System.out.println(gn(4,FooClass::fn)); // passing a reference to fn to act as a supplier

Functional Interfaces
Some functional abstractions have been added to the framework, among them being:
Supplier that supplies a type T by calling T get()
Consumer that consumes a type T by calling void accept(T t)
Function matches a function that takes T as an input and returns R as an output. R apply(T t)

Java still treats everything as a type. Supplier is a type, it is a functional interface. A functional interface is an interface with a single method.

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

Therefore, creating a supplier requires implementing this interface, Java supports anonymous implementation of interfaces. Say we don’t have a function to reference and we want to pass one anonymously

Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                return 10; // some magic number
            }
 };
// remember that gn takes a supplier 
System.out.println(gn(4,supplier));
}

This looks brilliant for a Java fan (WOW!! what a language) but it doesn’t look any brilliant for a functional chap. So much types and trivial code.

Supplier<Integer> supplier = return x;  
// Java : NOOO!!! you cant do that, bloody programmer. 
// Programmer: what a stupid compiler, I wanted to say 
//             that get returns x,it's obvious.
//             You know what, I gonna use C#, 
//             it supports lambdas I was told
// Java: Lambdas are not OOP
// Programmer: Fuck OOP
// Java: Hang on, I will add them to my 8th version
// Programmer: Cheers!!
}

And finally, lambda expressions were added to the language. Lambda expressions come from Lambda calculus. In simple words, if we have a simple computable function Sum(a,b) = a + b that takes two integers and it returns their sum,then this can be reworked into an anonymous form using lambda calculus to the following (a,b)->a+b.
In java 8 we can do the same, we can implement functional interfaces anonymously using lambda expressions.

Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("something cool");
            }
        };

Can be reworked to the following

Runnable runnable = () -> {System.out.println("something cool");}; 

On Side Note: You should use a higher level abstraction for concurrency.
Lambda expressions are very useful when working with datasets. Streams for instance are very lambda freindly because they use functional interfaces like Predicate and Function

int sum = shapes.stream()
                .filter(s -> s.getColour() == BLUE)
                .mapToInt(s -> s.getWeight())
                .sum();

Dont be shocked, you have to get familiar with this code. As you see, streams are declarative, this code
provides the WHATS rather than the HOWS and it’s the compiler responsibility to figure out the HOWS.
The imperative equivalent could be the following

int sum = 0;
for(Shape shape: shapes){
if(shape.getColour() == BLUE){
  sum += shape.getWeight();
}
}

Apart from verbosity, it’s quite hard to parallelise imperative code. On the other hand, it’s incredibly easy to parallelise such an aggregation using streams.

int sum = shapes.parallelStream()   // magic goes here
                .filter(s -> s.getColour() == BLUE)
                .mapToInt(s -> s.getWeight())
                .sum();

Test this version against a massive dataset to see the huge performance gain.

Streams are declarative and declarative is lazy and nothing beats being lazy.

List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
Stream stream = list.parallelStream().filter(c -> c % 2 == 0);
list.add(6);
System.out.println(stream.count());

Despite the fact that the 3rd even number was added after filtering even numbers, the output of this programme
is 3. Why? Because streams are lazy. The actual filtering is only get executed when required, and that is calling count which is a terminal expression does require an execution. A stream is an abstraction that takes our WHATS and works the HOWS out if and only if thats required.

We’ve recently mentioned the abstraction Function , which is an abstraction that matches a function that takes T and returns R. For example

 Function<Integer, Integer> function = (c) -> c + 1;
 // take an integer and top it up by a 1
 System.out.println(function.apply(5)); // apply it to 5

A practical example for this abstraction could be a memoiser. A memoiser that memoises calls for pure function.
In functional programming, purity means getting the same output out of the same input. Math.sqrt is a pure function, because every time you call Math.sqrt(4) you expect a 2. Calls for expensive pure functions could cached using simple memoisers.

class Memoiser {
    private final Map<Integer, Integer> cache = new HashMap<>();
    // pure expensive function
    int expensive(int x) {
        System.out.println("expensive");
        return x + 1;
    }

    void fn(int x) {
        if (cache.containsKey(x)) {
            System.out.println(cache.get(x));
        } else {
            cache.put(x, expensive(x));
        }
    }
}

Quite simple, expensive is pure and heavy, hence, it could be easily cached. If you look back at our memoiser, you might notice that it is not very abstract, it only works for expensive(int). Lets add more flexibility to it , instead of using expensive(int) directly, we can pass a higher order function that takes an integer and returns an integer.

class Memoiser{

    private final Function<Integer,Integer> higherOrderFunction;
    private final Map<Integer, Integer> cache = new HashMap<>();

    Memoiser(Function<Integer,Integer> function){
        this.higherOrderFunction = function;
    }

    void fn(int x) {
        if (cache.containsKey(x)) {
            System.out.println(cache.get(x));
        } else {
            cache.put(x, higherOrderFunction.apply(x));
        }
    }

}    

Hot Curries!!
All the functions we’ve seen so far take a single argument or none, the abstraction Function for instance matches a function that takes a single parameter. Cool, what about functions that take more than single parameter? Sum(a,b) for instance.

The equivalent of a Function in C# is Func. However, .Net provides a massive number of overloads for the type Func


Func<TResult> //matches a method that takes no arguments, and returns value of type TResult.
Func<T, TResult>//matches a method that takes an argument of type T, and returns value of type TResult.
Func<T1, T2, TResult>//matches a method that takes arguments of type T1 and T2, and returns value of type TResult.
Func<T1, T2, …, TResult>//and so on up to 16 arguments, and returns value of type TResult.

And Therefore the third option could be used in C# to match Sum

Func<int, int, int> sum = (c,c1) => c + c2;
Console.WriteLine(sum(2,3));

These overloads don’t exist in Java, so how we gonna deal with multiparam functions?? The solution is Currying. Haskell Curry, proved that any computed function that takes multi argument can be transformed into a chain of functions each with a single argument. So instead of returning the result immediately, we can return a function that has a full or partial computational knowledge of the result.
(a,b) -> a + b can be reworked to the following curried version (a) -> (a)-> a + b
The curried version returns a function that takes a single argument.

How does this look in Java?

Function<Integer,Function<Integer,Integer>> sum = a -> b -> a + b;
// apply 2 + 3
int result = sum.apply(2).apply(3);
System.out.println(result);

Declarative programming is a very powerful tool that should be used in your daily hacks, the days were imperative programming was the only methodology have gone. If you can’t see the point of using lambdas and functional stuff then you still a BLUB programmer. Blub programmers tend to see individual language features that they don’t understand as “weird”.
Happy hacking!!!!

Advertisements

Leave a Reply

Name and email address are required. Your email address will not be published.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

You may use these HTML tags and attributes:

<a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <pre> <q cite=""> <s> <strike> <strong> 

%d bloggers like this: