The more abstract a concept is, the harder it is to understand. Interfaces are abstract in nature. The more abstract they are, the more powerful they become, because they allow us to solve a wider range of problems apparently unrelated to a surprisingly small set of patterns.
The purpose of functional programming is to allow us to think less and write more descriptive codes.
The good news is that you don’t need to turn the key and everything is working in your head. You can apply functional approaches as you learn. I’ve been slowly studying this paradigm, and every day I see new ways of solving problems and each refactoring makes the code much more enjoyable.
Learning new programming paradigms is like learning a new instrument. After each note learned we increase our power of expression.
In my day-to-day work I use Functional Paradigm infrequently, but this foundation allows me to see problems in a different way and even to combine functional concepts with other paradigms such as Object Orientation. This has been a trend in the evolution of languages, in other other, we can unite the best of worlds. The example below in Typescript/Angular shows the union of functional concepts like map and Object Guidance concepts like the use of classes.
Multiple paradigms help you apply different ways of thinking about solutions to problems because solutions vary across languages.
Ultimately we will see that a stateless application is useless. But we always need to carefully select the points in the code where we allow the mutation to occur. Most of the internal parts of the code should strive to be immutable and therefore testable. The more mutations you can eliminate, the better.
Chip makers are on the atomic limits of transistor miniaturization. As a result, clock rates have not increased since 2004.
Multi-core is currently the preferred strategy for improving speed. Routines with shared mutable state cannot be distributed in parallel across multiple cores because they are not thread-safe.
As a suggestion follows Robert Martin’s lecture about this subject.
Just note: an “assignment statement” is totally benign a “reassignment statement” is problematic.
When you reassign (mutate) a variable you are introducing state change to your application. To reproduce a complex bug you often need the sequence of computations that lead to the failure. When you mutate variables you are throwing away that sequence.
Whenever you need to model a state change, you pass the previous value to a function that returns a new value. Don’t change the old value just return a new one.
Write functions that return changed copies instead of changing the properties of the specified object.
Objects are references, if we avoid changing their properties we avoid situations of unclear states. Also our finished code will be simpler to understand and easier to test.
Facebook’s Immutable.js is a small library that helps us keep our state immutable. There are other libraries that work in a similar way (Mori, seamless-immutable, acient-oak), but for this article we limit ourselves to Immutable.js.
Immutable.js provides many persistent immutable data structures including:
List, Stack, Map, OrderedMap, Set, OrderedSet and Record
Or in form of code:
Although we lose direct access to object properties, we can now focus on our goals, rather than fighting against mutations.
The plugin adds three rules:
Changing object properties is considered a mutation, in other words, a side effect by definition. We all learn that we should avoid side effects at all costs. We don’t need to examine the implementation of a function if it has no side effects. Our code gets easier to reason about and will be more predictable and more testable.
There are times when you need to stop and think if you are dealing with a value or a reference. Immutable objects are always values. This is one of the fundamental principles of functional programming. If I pass the value to a function, I can promise that it stays the same forever.
If you have objects that change very often, it isn’t a good idea to create a new instance for each change. This is especially true for games and simulations where this happens several times per second. I’m not saying that you can’t use immutability in games, but it is easier to fall into performance problems than in mutable objects.
If you have a huge data tree stored as an immutable container, I recommend checking your memory consumption. Of course, garbage collection kills all old objects, but copying large objects still has its price (Most frameworks on the market already handle this kind of problem very well).
In general, it is a pretty reasonable language design choice to take into consideration are the immutable types of data, since there are some problems that are simply not well modeled when everything is immutable. In most situations the advantages of immutable types vastly outweigh the disadvantages and they are better than the alternatives and lead to better code and faster executables overall.
As said at the beginning of the post, we don’t have to turn on a key to changing paradigms completely, we can start implementing immutable types gradually entering into more complex and useful patterns according to the need of our application. To end this post I leave @jamesiry’s tweet as a reflection.
Functional programmer: (noun) One who names variables “x”, names functions “f”, and names code patterns “zygohistomorphic prepromorphism” — James Iry
To be, or not to be a “Functional Programmer”, that is the question 😂
Create your free account to unlock your custom reading experience.