Question

In the following c# code example, the instance field [name] is readonly, and therefore is immutable after class construction.

public sealed class Example
{
    public readonly string name;

    public Example(string name)
    {
        this.name = name;
    }

    public string AllUppercase()
    {
        return this.name.ToUpper();
    }
}

The method [AllUpperCase] is idempotent and has zero side effects. However, the method depends on immutable state that is external to the method. Does this method qualify as being pure?

Was it helpful?

Solution

Yes, that function is effectively pure.

It has no side effects. It is idempotent. It depends on only inputs (including this) and those inputs are also pure.

Or to think about it another way assume AllUppercase was a static function that took an Example and used its name - that would of course be a pure function. Member functions are no different.

OTHER TIPS

When trying to think of dot notation from OO in terms of FP, it usually makes sense to consider the stuff before the dot as the first argument to a function. (So, think of x.f() as f(x) and x.f(y) as f(x,y))

Basically, this question boils down to the following: I have a pure function f and an immutable value x; is f(x) a pure function?

(f being ToUpper and x being this.name)

It seems better to call f(x) a value. Since it's a pure function applied to an immutable value, it's an immutable value.

Here are my two cents. A function in the mathematical sense is a mapping from input values to an output value, and nothing more. It does not print "Hello world!", and so on. It does not even compute anything.

Many programming languages use the term function to denote a self-contained piece of code that may take parameters and may return a value. Another term is procedure. Object-oriented languages have methods, which are procedures integrated with objects: they are invoked with the object itself as an implicit argument, and have access to the object's internal member variables.

When invoked, a procedure can perform a number of operations like reading from / writing to variables (memory locations) or IO devices (files, keyboard, and so on).

The term pure has been introduced to denote programming language functions (procedures) whose only effect is to compute a function in the mathematical sense: given some input values, they compute a result and return it.

Looking at the example of the OP. As other answers have pointed out, since AllUppercase() is invoked with the object itself as an implicit input, you can consider it a mapping from objects to strings. So

  1. For any given object, AllUppercase() will always return the same string, and
  2. invoking AllUppercase() has no observable effect other than what described at point 1.

Then AllUppercase() only computes a function in the mathematical sense, i.e. it is a pure function in the programming language sense.

Regarding the idea of a mutable input, pure input. I think it is important to define precisely what an input is and what same input means. Suppose that the member name in class Example were mutable. So now you invoke AllUppercase() and get one result. Then you mutate name, invoke the method again and get a different result.

  • If you define same input as "same memory location" (same object reference), then the function produced two different results with the same input ==> not pure.

  • If you define same input through object equality (the result of the 'Equals" method in C#), then AllUppercase() is still pure: when you invoke it on a mutated object, you are passing a different input so it is not a problem that it returns a different result.

Bottomline: to reason about purity when using mutable data you have to be precise about what you consider your inputs: addresses / variables or values contained in variables? This distinction is irrelevant when dealing with immutable data.

Licensed under: CC-BY-SA with attribution
scroll top