# Pure functions —JS: Functions

Functions in programming have a number of important characteristics. Knowing them enables us to determine more accurately how best to break code into functions and when we actually need to define them.

## Determinacy

The built-in JavaScript Math.random() function returns a random number between 0 and 1:

``````Math.random(); // 0.9337432365797949
Math.random(); // 0.5550694016887598
``````

The function is necessary and useful, but inconvenient in debugging and testing. This is because it can return different values for the same input (including missing arguments). Functions like this are called nondeterministic.

For example, functions that operate with system time are nondeterministic. For example, the Date.now() function returns a new value each time:

``````// Returns current time in milliseconds
Date.now(); // 1571909874844
Date.now(); // 1571909876648
``````

Here's an example with an input. Imagine a `getAge()`, function that takes as input the year of birth and returns the age:

``````getAge(2000); // ?
``````

Though running a function again right now will return the same value, a year from now it will be different. That is, a function is considered nondeterministic if it behaves that way at least once.

Deterministic functions, on the other hand, behave predictably. They always give the same result for the same input. These are the functions in mathematics.

It is interesting that, for example, the `console.log()` — function is deterministic. The point is that it always returns the same value for any input data. This is the `undefined` value, not what is printed on the screen, as one might think. Printing is a side effect, we'll talk about it a little later.

``````console.log('Hexlet – Big Bang');
``````

Calling `console.log('Hexlet - Big Bang')` performed two actions:

• Output the Hexlet - Big Bang message to the terminal (or browser console, depending on the runtime)
• Returned the `undefined` value. Whatever message we print, the return value will always be `undefined`.

A function also becomes nondeterministic if it accesses not only its arguments but also external data, such as global variables, environment variables, and so on. This is because the external data can change and the function will produce a different result, even if the same arguments are passed to it.

``````const getCurrentShell = () => process.env.SHELL;

getCurrentShell(); // /bin/bash
``````

The `getCurrentShell()` function accesses the `SHELL` environment variable. But at different times and in different environments, the value of this variable may be different.

Generally speaking, we cannot say that no determinacy is an absolute evil. Many programs and websites require a function that returns a random number or calculates the current date. On the other hand, it is in our power to divide the code so that it has as many deterministic parts as possible. A general recommendation when dealing with determinacy is to write a deterministic function if nothing is in your way. Don't use global variables, create functions that depend only on their own arguments.

The concept of Determinacy is not limited to programming or mathematics. Almost any process can be viewed through it. For example, flipping a coin is a nondeterministic process; the result is random.

## Side effects

The second key feature of the functions is the presence of side effects. Side effects are any interactions with the external environment. These include file operations such as writing to a file, reading a file, sending or receiving data over the network, and even output to the console.

``````const someFunction = () => {
// The function fetch performs an HTTP request
// HTTP request is a side effect
fetch('https://hexlet.io/courses');
};
``````

In addition, changes to external variables (e.g., global ones) and inputs when they are passed by reference are considered side effects.

``````const someFunction = (obj) => {
// Some kind of logic
// Side effect. Changing the input argument.
obj.key = 'value';
};
``````

Computation (logic), on the other hand, has no side effects. For example, a function that sums up two numbers given as arguments.

``````const sum = (num1, num2) => num1 + num2;
``````

Side effects are one of the biggest challenges in development. Their presence makes code logic and testing much more difficult. Leads to a huge number of errors. When working with files alone, the number of possible errors is measured in hundreds: from running out of disk space to trying to read data from a non-existent file. To keep code from such errors requires a large number of checks and protection mechanisms.

It is impossible to write any useful program without side effects. Whatever important calculations she does, their result must somehow be demonstrated. In the simplest case, you have to display it on the screen, which automatically leads us to side effects:

``````console.log(sum(4, 11)); // => 15
``````

In real-world applications, however, it usually comes down to interacting with the database or sending queries over the network.

There is no way to get rid of side effects altogether, but their effect on the program can be minimized. Generally, there aren't many side effects in a common program relative to the rest of the code, and they occur only at the beginning and at the end. For example, a program that converts a file from text format to PDF ideally performs exactly two side effects:

1. Reads the file at the beginning of the program.
2. Writes the result of the program to a new file.

Between these two points is the main work, which contains the pure algorithmic part. The side effects will then only reside in the top layer of the application, and the core part that does the main work will remain pure.

Increment and decrement are the only basic arithmetic operations in JS that have side effects (they change the variable value itself). This is why they are difficult to work with in compound expressions. They can lead to errors so hard to catch that many languages have refused to introduce them at all (Ruby and Python have none).

## Net functions

An ideal function in terms of convenience is called pure. A pure function is a deterministic function that produces no side effects. Such a function depends only on its input arguments and always behaves predictably.

Pure functions have a number of key advantages:

• It's easy to test them. It is enough to pass the required parameters to the input of the function and see the expected output.
• They are safe to re-run, which is especially relevant in asynchronous code or in the case of multithreaded code.
• They are easy to combine to get new behavior without having to rewrite the program (more on that later in the course).

Well-designed programs try to isolate side effects in a small part of the application so that most of the code remains pure.

Right now, this may sound rather abstract. Understanding this topic requires more than just comprehending the words before you but also a knack for the complexity of working through a mishmash of side effects. We will raise the topic of cleanliness on a regular basis. It's especially hard to work out in projects, on live code.

## Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

## For full access to the course you need a professional subscription.

130
courses
1000
exercises
2000+
hours of theory
3200
tests

• 130 courses, 2000+ hours of theory
• 1000 practical tasks in a browser
• 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Suggested learning programs
profession
Development of front-end components for web applications
10 months
from scratch
Start at any time