Say we have a normal pure function such as
function add(a, b) {
return a + b
}
And then we alter it such that it has a side effect
function add(a, b) {
writeToDatabase(Math.random())
return a + b;
}
It’s not considered a pure function as far as I know because I often hear people call pure functions “functions without side effects.” However, it does behave like a pure function as far as the fact that it will return the same output for the same inputs.
Is there a different name for this type of function, is it unnamed, or is it still actually pure and I’m mistaken about the definition of purity?
16
I’m not sure about universal definitions of purity, but from the point of view of Haskell (a language where programmers tend to care about things such as purity and referential transparency), only the first of your functions is “pure”. The second version of add
isn’t pure. So in answer to your question, I’d call it “impure” 😉
According to this definition, a pure function is a function that:
- Only depends on its input. That is, given the same input, it will always return the same output.
- Is referentially transparent: the function can be freely replaced by its value and the “behavior” of the program will not change.
With this definition, it’s clear your second function cannot be considered pure, since it breaks rule 2. That is, the following two programs are NOT equivalent:
function f(a, b) {
return add(a, b) + add(a, b);
}
and
function g(a, b) {
c = add(a, b);
return c + c;
}
This is because even though both functions will return the same value, function f
will write to the database twice but g
will write once! It’s very likely that writes to the database are part of the observable behavior of your program, in which case I’ve shown your second version of add
isn’t “pure”.
If writes to the database aren’t an observable part of your program’s behavior, then both versions of add
can be considered equivalent and pure. But I can’t think of a scenario where writing to the database doesn’t matter. Even logging matters!
8
What do you call a function [for which] the same input will always return the same output, but also has side effects?
Such a function is called
deterministic
An algorithm whose behavior can be completely predicted from the input.
termwiki.com
Regarding state:
Depending on whose definition of a function you use, a function has no state. If you come from the object oriented world, remember that x.f(y)
is a method. As a function it would look like f(x,y)
. And if you’re into closures with enclosed lexical scope remember that immutable state might as well be part of the functions expression. It’s only mutable state that would impact the functions deterministic nature. So f(x) = x + 1 is deterministic so long as the 1 doesn’t change. Doesn’t matter where the 1 is stored.
Your functions are both deterministic. Your first is also a pure function. Your second is not pure.
Pure function
The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices.
Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.
wikipedia.org
Point 1 means deterministic. Point 2 means referential transparency. Together they mean a pure function only allows its arguments and its returned value to change. Nothing else causes change. Nothing else is changed.
16
If you don’t care about the side effect, then it’s referentially transparent. Of course it’s possible that you don’t care but someone else does, so the applicability of the term is context-dependent.
I don’t know of a general term for precisely the properties you describe, but an important subset are those that are idempotent. In computer science, slightly differently to in mathematics*, an idempotent function is one that can be repeated with the same effect; that is to say the nett side-effect result of doing it many times is the same as of doing it once.
So, if your side-effect was to update a database with a certain value in a certain row, or to create a file with exactly consistent contents, then it would be idempotent, but if it added to the database, or appended to a file, then it would not.
Combinations of idempotent functions may or may not be idempotent as a whole.
*The use of idempotent differently in computer science than mathematics appears to have come from an incorrect use of the mathematical term that was then adopted because the concept is useful.
3
I don’t know how such functions is called (or whether there even is some systematic name), but I would call function that is not pure (as other answers cowered) but always returns same result if supplied with same parameters “function of its parameters” (compared to function of its parameters and some other state).
I’d call it just function, but unfortunately when we say “function” in context of programming, we mean something that does not have to be actual function at all.
1
It basically depends on whether or not you care about the impurity. If the semantics of this table are that you don’t care how many entries there are, then it’s pure. Else, it’s not pure.
Or to put it another way, it’s fine as long as optimizations based on purity don’t break program semantics.
A more realistic example would be if you were trying to debug this function and added logging statements. Technically, the logging is a side effect. Do the logs make it impure? No.
10
I’d say that the best thing to ask is not how we would call it, but how we would analyze such a piece of code. And my first key question in such an analysis would be:
- Does the side effect depend on the argument to the function, or the result on the side effect?
- No: The “effectful function” can be refactored into a pure function, an effectful action, and a mechanism for combining them.
- Yes: The “effectful function” is a function that produces a monadic result.
This is straightforward to illustrate in Haskell (and this sentence is only half a joke). An example of the “no” case would be something like this:
double :: Num a => a -> IO a
double x = do
putStrLn "I'm doubling some number"
return (x*2)
In this example the action that we take (print the line "I'm doubling some number"
) has no impact on the relationship between x
and the result. This means we can refactor it this way (using the Applicative
class and its *>
operator), which shows that the function and the effect are in fact orthogonal:
double :: Num a => a -> IO a
double x = action *> pure (function x)
where
-- The pure function
function x = x*2
-- The side effect
action = putStrLn "I'm doubling some number"
So in this case I, personally, would say that it’s a case where you can factor out a pure function. A lot of Haskell programming is about this—learning how to factor out the pure parts from the effectful code.
An example of the “yes” sort, where the pure and the effectful parts are not orthogonal:
double :: Num a => a -> IO a
double x = do
putStrLn ("I'm doubling the number " ++ show x)
return (x*2)
Now, the string that you print depends on the value of x
. The function part (multiply x
by two), however, doesn’t depend on the effect at all, so we can still factor it out:
logged :: (a -> b) -> (a -> IO x) -> IO b
logged function logger a = do
logger a
return (function a)
double x = logged function logger
where function = (*2)
logger x putStrLn ("I'm doubling the number " ++ show x)
I could go on spelling out other examples, but I hope this is enough to illustrate the point I started with: you don’t “call” it something, you analyze how the pure and the effectful parts relate and factor them out when it is to your advantage.
This is one of the reasons Haskell uses its Monad
class so extensively. Monads are (among other things) a tool for performing this sort of analysis and refactoring.
Functions that are intended to cause side-effects are often called effectful. Example https://slpopejoy.github.io/posts/Effectful01.html
4