9

I'm trying to figure out a way to handle default variable values when making functions without side effects and have ended up with the following:

function getDefaultSeparator() {
    return ':';
}

function process(input, separator) {
    var separator = separator || getDefaultSeparator();

    // Use separator in some logic

    return output;
}

The default separator will be used in other functions and I only want to define it in one place.

If this is a pure function, what is the difference from just using a global DEFAULT_SEPARATOR constant instead?

  • 5
    There isn't any material difference, unless you're planning on using the function as a placeholder for some logic to be added later. – Robert Harvey Mar 14 '16 at 14:47
  • 3
    Possible duplicate of Is a function immediately impure if it takes a function as a parameter?. The question isn't an exact duplicate, but the answer should be the same. ("It depends on the purity of the other function.") – jpmc26 Mar 14 '16 at 18:55
  • 1
    Using a global constant doesn't make a function impure. Using a global value that you assume is constant does. – chepner Mar 14 '16 at 19:08
  • Btw, you can curry process (with reversed parameter order) and than specialize the curried function to var processDefault = process(":") – bob Mar 17 '16 at 12:10
22

Is a function getting a value from another function considered pure?

That depends on what the other function does, and what the calling function does. Impurity is infectious, purity isn't.

Calling a pure function doesn't change the purity of the calling function. Calling an impure function automatically makes the calling function impure also.

So, in your example, it depends on the purity of the part you left out: if that is pure, then the whole function is pure.

If this is a pure function, what is the difference from just using a global DEFAULT_SEPARATOR constant instead?

Nothing. A function that always returns the same value is indistinguishable from a constant. In fact, that is exactly how constants are modeled in λ-calculus.

  • 2
    "Calling an impure function automatically makes the calling function impure also" Are you quite sure about that? AFAICS, calling an impure function does not automatically make the caller impure, though doing it might. – Deduplicator Mar 14 '16 at 17:11
  • 2
    @Deduplicator: depends how much static analysis you can (be bothered to) do. Sure, if there's a function func that has side effects when you pass in 0, but not when you pass in 1, then you can reasonably say that although func itself "is impure", a function calling it as func(1) (and ignoring the return value, let's say) is not necessarily impure. Calling func is enough to "taint" the caller as being potentially impure, but a tainted function might by some means be proven to be pure after all. At least in javascript, where pure/impure isn't defined within the language. – Steve Jessop Mar 14 '16 at 17:22
6

Yes, those are both pure functions (assuming the elided part is also pure) because:

  1. The result depends only on the parameters.
  2. There are no side effects.

Note that if getDefaultSeparator() was not a pure function, then neither would process() be pure.

In Javascript, there's no meaningful difference between using a pure function or a constant and both can be used by pure function, as long as Javascript's ability to redefine functions or alter the values of constants is avoided.

A key concept behind pure functions is that they could be replaced with the value they return without affecting the results of the program.

1

As the others are saying, sure, it is still a pure function.

However, let's talk about the design issues. You are right to try to do something to keep the code DRY, by putting the value in only once place. In addition, what I think also should be considered is the level of coupling that is appropriate.

Using a function gives you more flexibility to change the implementation, which is to say that the function approach offers looser coupling than a global variable.

The question is whether one needs it or not?

If consumers and the provider are in the same module, and the provider is private to the module, it is hard to argue that this level of loose coupling is necessary, due to the fact that if the provider requires upgrade from a private variable to a private method, a simple refactoring within the module can be applied to the consumers at the same time. Using a method/function before you really need could fall under YAGNI.

Even if the consumer(s) and provider are in different modules, yet the modules are versioned together (for example, you use a minifyer, so that the modules of the consumers and provider are in the same file), YAGNI may also apply.

On the other hand, if, for example, the producer is in a library or API package or module that is versioned separately from the consumer(s), then using the function may be appropriate. In that case we should be looking at longevity of the API, and principles like OCP.

(On another note, if your code is of any significant size, I would encourage the use of modules with fields and methods rather than global variables and functions.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.