📜 ⬆️ ⬇️

Is it possible to consciously refuse functional programming?

Functional programming pervades much of the core world of programming — the JavaScript ecosystem, Linq for C #, even high order functions in Java. This is what Java looks like in 2018:

getUserName(users, user -> user.getUserName()); 

Functional programming is so useful and convenient that, as far as I can see, has penetrated into all modern common languages.

But not everything is so rosy. Many developers resist this tectonic shift in our approach to software. Honestly, today it is difficult to find a job related to JavaScript, which does not require knowledge of the concepts of AF.

Functional programming underlies both dominant frameworks: React (architecture and one-way data transfer was created to avoid common variable DOM) and Angular (RxJS is a library of utility operators that are widely used throughout the framework using higher-order functions). Redux and ngrx / store are also functional.
')
Beginners may be frightened by the OP approach, and for the sake of quickly drawing into the work, someone from your team can suggest getting used to the code base by refusing the OP .

For managers who are unfamiliar with the FI itself or its influence on the modern programming ecosystem, such a proposal may seem reasonable. In the end, isn't the PLO faithfully serving us for 30 years? Why not leave everything as it is?

Let's deal with the wording itself. What does “ban” of FP at the policy level mean in general ?

What is functional programming?


My favorite definition:

Functional programming is the paradigm of using pure functions as indivisible units of composition, with the avoidance of a common changeable state and side effects.

Net function:


That is, the essence of the OP is reduced to:


Putting it all together, we get software development with building blocks in the form of pure functions (indivisible units of composition).

By the way, Alan Kay (the founder of the modern OOP) believes that the essence of object-oriented programming is:


So OOP is just another way to avoid common alterations and side effects.

Obviously, the opposite of the OP is not OOP, but unstructured, procedural programming.

The Smalltalk language (in which Alan Kay laid the foundations of OOP) is both object-oriented and functional , and the need to choose one thing is an alien and unacceptable idea.

The same is true for javascript. When Brendan Eich was hired to develop this language, his main idea was to create:


In JavaScript, you can try to stick to one paradigm, but, for good or not, they are both inextricably linked. JavaScript encapsulation depends on closures - a concept from the OP.

Surely you are already using functional programming, perhaps without even knowing it.

How to NOT use OP


To avoid functional programming, you have to avoid using pure functions. But then you will not be able to write such code, because it may turn out to be clean:

 const getName = obj => obj.name; const name = getName({ uid: '123', name: 'Banksy' }); // Banksy 

Let's refactor the code so that it no longer refers to the OP. You can make a class with a public property. Since encapsulation is not used, it would be an exaggeration to call this the PLO. Perhaps "procedural object programming"?

 class User { constructor ({name}) { this.name = name; } getName () { return this.name; } } const myUser = new User({ uid: '123', name: 'Banksy' }); const name = myUser.getName(); // Banksy 

Congratulations! We have just turned 2 lines of code into 11, and also introduced the possibility of an uncontrolled external mutation. And what did you get in return ?

Well, actually, nothing. In fact, we have lost in universality and opportunities for significant code savings .

The previous getName () function worked with any incoming object. The new function also works (because it is JS and we can delegate methods to any objects), but it turns out much more clumsy. You can allow two classes to inherit from the normal parent class, but this implies an unnecessary relationship between the classes.

Forget about reuse. We just flushed it down the toilet. This is how code duplication looks like:

 class Friend { constructor ({name}) { this.name = name; } getName () { return this.name; } } 

A diligent student from the back of the desk will exclaim, “Well, create a person class!”

Then:
 class Country { constructor ({name}) { this.name = name; } getName () { return this.name; } } 

“But these are different types. Of course , you cannot apply the person class method to a country! ”.

To this I answer: "Why not?"

One of the incredible advantages of functional programming is the trivial simplicity of generalized programming. We can call this “generalization by default”: the ability to write one function that will work with any type that satisfies its generalized requirements .

Note to Java programmers: this is not about static typing. Some FP languages ​​have excellent static type systems, but still enjoy the benefits of structured types and / or HKT (higher-kinded types).

This is an obvious example, but the resulting code savings are huge .

This allows libraries like autodux to automatically generate domain logic for any object created from a getter / setter pair (and many others). We can also reduce the amount of domain logic code by half, or even more.

No more higher order functions.


Since many (but not all) higher-order functions take advantage of pure functions to return the same values ​​when receiving the same input data, you cannot use functions like .map(), .filter(), .reduce() without causing side effects .map(), .filter(), .reduce() :

 const arr = [1,2,3]; const double = n => n * 2; const doubledArr = arr.map(double); 

Becomes:

 const arr = [1,2,3]; const double = (n, i) => { console.log('Random side-effect for no reason.'); console.log('Oh, I know, we could directly save the output to the database and tightly couple our domain logic to our I/O. That will be fine. Nobody else will need to multiply by 2, right?'); saveToDB(i, n); return n * 2; }; const doubledArr = arr.map(double); 

Rest in peace, the composition of the function. 1958–2018


Forget about point-free-composition of higher order components to encapsulate end-to-end functionality on pages. This convenient, declarative syntax turns into a taboo:

 const wrapEveryPage = compose( withRedux, withEnv, withLoader, withTheme, withLayout, withFeatures({ initialFeatures }) ); 

You will have to manually import all this into each component, or even worse - to plunge into a tangled, inflexible hierarchy with class inheritance (which most conscious citizens, and even (especially?) The canon of object-oriented programming rightly recognize as antipattern ).

Goodbye promises and async / await


Promises are monads. Technically, they belong to the theory of categories, but I heard that promises still belong to the OP, also because in Haskell they are used to ensure cleanliness and laziness (lazy).

Honestly, it is not so bad to get rid of monads and functors. They are much easier than we expose them! I do not just teach people how to use Array.prototype.map and promises before talking about the general concepts of functors and monads.

Do you know how to apply them? So you are halfway to understanding functors and monads.

So, to avoid functional programming



And say goodbye to:


Avoid functional programming? No problem.
Or wait a minute ...

Source: https://habr.com/ru/post/354880/


All Articles