preface

For clarity, remember that side effects are not necessarily bad, and sometimes they can be useful (especially outside of the functional programming paradigm).

Today I’m going to talk about the idea of isolation in functional programming. It wants to isolate “side effects.”

Let’s talk about side effects from a different perspective.

Side effects in life

If I hear the word side effect, my first reaction is to take medicine 💊.

The old saying is that three parts of the medicine are bad, and three parts are side effects. For example, you 👹 caught a cold, ate some patent drugs developed by some western countries, and then caught a cold, but after catching a cold, you found yourself bald 👹đŸŠČ.

So baldness is a side effect of this cold medicine.

So let’s go through this logic

  • Have you got rid of your cold? A: ok
  • Does this medicine count as cold medicine? Answer: calculate cold medicine
  • If you don’t take this medicine, you won’t get rid of your cold. A: to eat
  • Can the side effects be tolerated? Answer: at least have no hair to be able to endure

The side effects are somewhat exaggerated, but medications generally have some side effects.

So what about the program?

What are the side effects of the program

In the I/O model, we expect only computations between I and O, and if that includes, and not only includes, anything that triggers other I/ OS that is not related to the I -> O calculation, that is a side effect.

Why is it called a side effect? The word “side effect” is bad at first, and it’s supposed to put you on your guard. If some side effect happens between I/O that we don’t know about, then we can’t control the process and the testing process becomes very complicated.

As you can imagine, if you want to access a database between I/ OS, you must ensure that the database is running. If you want to write to a file, you must ensure that the file exists and is open. So the execution process and the testing process become very complicated, not a single point-to-point.

Writing this reminds me of the 872 test cases provided by the PromiseA+ specification that Promise promises must pass.

No side effects advantage

What are the advantages of an I/O model without side effects? Let’s go back to the original life example.

If the cold medicine is replaced by a medicine produced in an Oriental country without side effects, when we catch a cold, we can take the cold medicine and get rid of it. Process without any side effects, not balding.

Then we can safely take this medicine in the case of a cold, regardless of other conditions. This is a pure I/O model.

In programming, we declare a function double, as follows

Double returns identity and 6 each time x = 3 is typed. It doesn’t depend on anything other than the arguments we pass it.

As you can imagine, all sorts of things are happening on earth when we call double. If ultraman appears in the sky at the moment of the call, double still outputs 6. It’s eternal in the case of a fixed input.

When you write this function, you can safely use it for the rest of your life, no matter the context, and it will work forever.

Timeless things change less frequently, are easier to test, and easier to debug. This is why many programming languages today tend to be side-effect-free.

The concept of side effects in functional programming

If a function has side effects, we call it a procedure

Functional programming is based on the simple premise that there are no side effects. In this paradigm, side effects are excluded.

If a function has side effects, we call it a procedure, or imperative. So the function has no side effects. We believe that if a function modifs a mutable data structure or variable, uses I/O, throws an exception or abort error, it will have side effects. All of these things are considered side effects.

Side effects are bad because (if there are) side effects, depending on the system state, the functionality can be unpredictable. When a function has no side effects, we can execute it at any time, and given the same input, it will always return the same result.

But to be clear, functional programming does not eliminate side effects, just limit them when needed.

There need to be side effects, because without them, our program would just do calculations.

We often have to write databases, integrate with external systems, or write files. Interacting with the outside world in the form of interfaces is what makes our calculations visible. So the central idea of many languages that tend to be side-effect-free is to treat “effects” and “side effects” separately.

Let’s look at it through some features.

With reference to transparent

A function that always returns the same result for the same input is called a pure function. Thus, a pure function is a function that has no observable side effects, and if the function has any side effects, it may return different results even if we call it with the same arguments. So we can replace the pure function with its calculated value, for example:

If we input x = 2, y = 2, then we get 4 = sum(2, 2).

So is sum a pure function? Obviously yes, if we pass constant x equals 2, y equals 2. So sum is going to be equal to 4.

So that means that f(2, 2) can be replaced by 4, for example math.floor (sum(2, 2)) is the same as math.floor (4).

It’s like a big query table. We can do this because it doesn’t have any side effects. The ability to replace an expression with its computed value is called referential transparency.

Reference transparency is important because it allows us to replace expressions with values. This property enables us to think and reason about program evaluations using substitution models. Thus, expressions that can be replaced with values can be said to be deterministic because they always return the same value for a given input.

Local side effect

Before we talk about local side effects, let’s take a typical example of a non-local side effect 🌰.

Does the factorial function above have side effects?

A: Apparently there is. There is a visible interaction inside the function with the outside, and the outside result value is modified inside the function. And the first call to factorial(2) returns 3 and the second call returns 6. You cannot always return the same result for uniform input. This side effect is rejected by the idea of functional programming, where the interaction with the outside world makes factorial uncertain.

Let’s look at another example 🌰

So the question is, does factorial have a side effect this time?

A: There is a side effect because result changes the return value of factorial each time for is executed.

But even then, factorial of 2 can be replaced by a value, if you think of factorial as a black box, you can’t see the side effect from the outside. Every time x = 2 is entered, there is always a fixed return value of 3.

In other words, the function is deterministic, and the feature we’re talking about has local side effects, but users of the feature don’t care because it doesn’t break our alternative pattern. Thus, even with local side effects, the function is pure. This is why the above statement “produces visible interaction” is obviously so strict that if it is not seen, it is still pure.

In functional programming development, you can use tricks, such as containers, to keep some of the side effects locally for pure purposes.

Give some typical examples of side effects

Think about it, but here are some typical examples of side effects to better understand the idea.

1. Interacting with the outside world.

2. Call I/O

Retrieve values from outside the scope of a function

4. Disk retrieval

5. Throw an exception

END

With the side effects of functional programming isolated, what is left are pure functions, that is, pure functions, which are performed with pointfree ideas. See you next ~

After all, what this article expounds is a kind of idea. Although simple examples are given throughout, the idea is the same. I wanted to express an idea in vernacular rather than in a mass of official words. This is easier for the reader to understand.

When we think differently, our code changes as a whole: process-oriented, object-oriented, slice-oriented, results-oriented… , etc.

Projects are built with snippets of code, so we’re looking at small snippets of code. Look at the small and see the big.

Previous articles are recommended

  • Hindley-milner in Functional Programming
  • The Mathematics of Functional Programming
  • Drag components: React-DND usage and Source Code