skip to Main Content

Is this function pure or impure?

function greet(name) {
    return "Hi I'm " + name;
}

The property of pure function is that it has no side effects and always returns the same output for the same input.

Here, it produces side effects (returning a string).
The string concatenation, "Hi, I'm " + name, introduces a dependency on external state. Impurity is made from "Hi, I’m " .

We can rewrite the code below to make it pure.

//pure function
function pureGreet(greeting, name) {
    return greeting + name;
}

//console output
const hiGreeting     = "Hi, I'm ";

const actualGreeting = pureGreet(hiGreeting, "John");

console.log(actualGreeting);

Is this explanation correct?

2

Answers


  1. No, that explanation isn’t correct.

    Here, it produces side effects (returning a string)

    No, returning a value is not a side effect. That’s what functions do.

    The string "Hi I'm " is a constant, so that doesn’t change the characteristics of what constitutes referential transparency:

    • Does it always return the same output given the same input? Yes.
    • Does it have any side effects? No.

    Therefore it’s a pure function.

    Constants are just constants. You could imagine another function that always adds 2 to its input:

    function add2(i) {
        return 2 + i;
    }
    

    This is pure as well, since 2 is a constant. add2(2) always returns 4, and add2(3) always returns 5, and so on.

    The string concatenation, "Hi, I’m " + name, introduces a dependency on external state

    The string "Hi, I'm " is actually not external to the function body, but an implementation detail.

    That said, depending on external state is not in itself cause for impurity, as long as that external state is immutable. That’s what closures do.


    There is, by the way, a subtle distinction between purity and referential transparency that Tyson Williams has pointed out to me. It mostly becomes important in languages like Haskell, but the bottom line is that you can have referentially transparent functions with ‘impure implementations’. The F# base library does this a lot.

    If you’re really interested, I don’t know of a better place to link to than the long thread where Tyson Williams originally made me aware of that distinction: https://blog.ploeh.dk/2020/02/24/discerning-and-maintaining-purity/#d28c24c07228400f9ed141f97b5c72b5

    Login or Signup to reply.
  2. Be careful that you aren’t mixing up different layers of abstraction when pondering these sorts of things.

    If you dig down far enough, there’s no such thing as a pure function: side-effects are happening like memory allocations, swaps, moves, etc. Go down another level and transistor states are changing in silicon wafers, heat is being produced and redirected, etc.

    But that’s usually the wrong layer at which to consider "does this function have side-effects" even in a manually managed language like Rust or C: the question you should be asking is "does the caller always get back the same returned value for the same inputs?"

    There are exceptions but they’re rare: for instance if you are writing an OS kernel then it may matter very much whether a function could potentially allocate memory because that allocation might fail and you can’t just crash or have random behavior. But usually we don’t worry about that and can safely treat that sort of thing as an implementation detail that normally doesn’t leak out.

    So it depends: in what context are you asking the question? Because in the context of the Javascript example you posted that function is pure at any level you could possibly be concerned about when writing Javascript. But in another context/language you might be worried about the implicit side-effect of the allocation to hold the concatenated string.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search