Rio: Hello Mr Archie, I have a question for you. I am not able to understand actually what is functional programming? I have always been reading about that while using functional programming we need to forget everything we know about programming. How can we forget about the variable, values, functions, datatypes, indentation, name spaces, hashes, collections, classes, inheritance etc. This statement is quite confusing. Could you please help me understand about the actual idea behind functional programming?
Mr Archie: Hey Rio, that indeed is a very good question. I would try to explain in an easy manner. The above statement should actually be corrected. The functional programming is all about refactoring everything you know about programming.
Let me try to explain what do I mean by both the above statement, Even in a very well designed applications with time, requirement changes or bug fixes need to be implemented/fixed which lead to many changes that leads to re-designing, adding new modules or removing few existing ones. All these factors make the existing design a mess. The subsequent bug fixing will be even harder in such kind of messed up design. There are lots of if else condition introduced many times. This is kind of very generic problem with most of the object oriented programming languages like I can give an example of type erasure process in java which is "Replace all parameters with their bound classes if the parameter is bounded or replace it with Object class if the parameter is unbounded". These kind of if else statements would make one finally feel that the code needs to be refactored by keeping the well designed modules as is and re-organizing (re-factoring) the badly designed modules and introducing fewer new ones to keep the application outcome same as it was earlier. Now in order to bind the above constructs together in functional programming, we introduce functions as a bridge between them. These functions are written in such a manner that
- There are no side effects on the function being called, which means there should be no change in the state of input variables. This can be achieved e.g by using immutable input parameters. e.g say if an x = {3, 4, 5} is applied over a function y which is f(x), at the end of evaluation of y the value of x should still remain {3, 4, 5}. Now a question will arise in your mind that what if the parameters passed are something like array of hash-maps which are mutable. For this we actually always need to make sure that such data structures are immutable. Another question will now come into your mind that if everything is immutable how can we apply logic what needs to be performed. For this, we have to make sure that our data structure should be having an operation to return create a copy of itself which are mutable. To limit the number of copies while creating required mutable data structure, efficient persistent data structures were introduced. These are actually mutable and support copy on modification operation.
- There are final desired effects produced as per the requirement of the application (enduser). That means we need to implement mutable state now into the application. This can be done by using bridges between the above function with (no side effect) on one side and the business logic on the other which will give the desired result. The function is thrown at the bridge which performs the desired logic. Examples of such bridges are Atomic classes, messaging queues etc which perform the task of producing desired final results.
Here we can think about programming functions just as mathematical function say f(x) which is an nothing but an abstract relationship between input set and output set. These will always give us same output for the same set of input.
Rio: Why do we call them persistent data structure? It does not seem to be having any relation to database here.
Mr Archie: Yeh actually it was unfortunate by the designers of functional programming paradigm to use the term persistent here. Actually they are called efficient persistent data structures as they always store the previous version/copy of themselves when modified. Even if they are storing every copy while applying any modification, they are written so efficiently that the minimum copies are created via using data structures like trees/graphs etc using branching factor of 32 which can support millions of elements. Only the node where modification is done is copied, the rest nodes are still pointing to the original data structure.
Rio: What is the biggest benefit of using functional programming?
Mr Archie: Sure, few of the benefits achieved by using functional programming approach are as below
- There are no assignments statements in functional programs, so the variables are immutable
- We don't need to worry much about multithreading as the input data is immutable.
- Since there are no side effects, so there is very less chance of introducing bugs.
- Since the functions are referentially transparent, which means independent of each other, so the order of the program statements need not to be imperative.
Rio: And what are first class functions in programming language?
Mr Archie: A function that can take another function as a parameter or can even return a function as an output is called a first class function.
Rio: If I ask you specifically about how do we use functional programming in Java.
Mr Archie: The ways with which we use functional programming in java are:
- Using Anonymous inner classes where we can create and instantiate a class at the same time. This is used if we want to use class declaration just once.
- Using Lambda Expression or anonymous functions which can accept parameters and return a value.
- Using Method References.
Rio: The concept of Method reference was introduced in java 8, if I am not wrong. Can you please elaborate a bit how we can used method references in functional programming?
Mr Archie: Off-course, why not. Method references are nothing but a special type of lambda expression. They are called method references as they refer to an existing method. They can be used in 4 ways. I will explain all one by one
The String Utils class a static method capitalize(String string) which converts given string to all capital cases. This can be achieved as below
public class MethodReferenceForStaticMethods {
public static void main(String[] args) {
List<String> list = List.of("rio", "mr. achie");
list.stream().forEach(word -> {
StringUtils.toRootUpperCase(word);
});
}
}
The same result can also be achieved using method references as below
public class MethodReferenceForStaticMethods {
public static void main(String[] args) {
List<String> list = List.of("rio", "mr. achie");
list.forEach(StringUtils::toRootUpperCase);
}
}
- Referring instance method
If an instance method of a class is having same number of arguments as present in a functional interface, the instance method can be referred as below
public class MethodReferenceForInstanceMethods {
public static void main(String[] args) {
MethodReferenceForInstanceMethods instance =
new MethodReferenceForInstanceMethods();
MyFunctionalInterface methodReferenceForInstanceMethods =
instance::instanceMethod;
methodReferenceForInstanceMethods.say("a", "b", 5, 8);
}
public void instanceMethod(
String a, String b, int c, Object d
) {
System.out.println("Hello, this is non-static method by: "
+ a + " " + b + " " + c + " " + d);
}
interface MyFunctionalInterface {
void say(String a, String b, int d, Object e);
}
}
Rio: Thank you so much Mr Archie for making me understand the paradigm of functional programming in such a simple way. I will get back to you with more queries about it in coming days.
Mr Archie No issues, you can come over to me at any time.