5

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?

  • 3
    Rather that categorically declaring this method "pure," I would use the more accurate terms "depending on external but immutable state," "idempotent" and "doesn't cause side-effects." Genuinely pure methods produce the same output given the same input, but the input to this method comes to the method indirectly through the class instantiation (and not through a method parameter), so I wouldn't categorize it as "pure." Pure methods are generally self-contained. – Robert Harvey Oct 21 '16 at 1:58
  • Perhaps, @RobertHarvey, you can put this as an answer. Does purity absolutely require inputs to be direct inputs? – Rock Anthony Johnson Oct 21 '16 at 2:02
  • 4
    I've never actually considered "purity" as applied to methods instead of functions. I guess it all depends on your point of view. The this parameter is implicit, but it's still a parameter – gardenhead Oct 21 '16 at 2:27
  • 2
    Why are you calling this a class-level field? This is an instance field. Saying class-level makes it sound static. – Erik Eidt Oct 21 '16 at 16:03
  • 1
    A pure function can use values that are defined outside of it. What makes a function pure is that its output is determined purely from its inputs (i.e. it behaves like a function as defined in mathematics). For every possible input, the function will always produce the same result when given that input. – Doval Oct 24 '16 at 15:34
12

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.

  • 1
    A pure input doesn't make any sense. Purity in general only refers to functions, not arbitrary values. – gardenhead Oct 21 '16 at 2:25
  • @gardenhead - consider the name accessor like a getter property. It's a slightly odd use of the terminology, I admit, but the concept is the same. – Telastyn Oct 21 '16 at 2:27
  • I don't see what you mean. The way I like to view objects has this as a record-type (struct) with all the instance variables as fields. To the input to AllUpperace() would be this, not name, which is merely a field of this. – gardenhead Oct 21 '16 at 2:30
  • @gardenhead the "pure input" makes complete sense. If name were mutable, then AllUppercase would be non-deterministic. Trying to view non-deterministic functions as pure would render the "pure function" term meaningless. – David Arno Oct 21 '16 at 6:50
  • @DavidArno That depends on whether you consider this to be an external variable or an implicit parameter to the function. – gardenhead Oct 24 '16 at 16:03
6

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.

  • 1
    "Since it's a pure function applied to an immutable value, it's an immutable value.": Can you explain this last statement? All values are immutable, there is no such thing as a mutable value. E.g., 1, 2.4, "Hello, world" are all values and are all immutable. – Giorgio Oct 21 '16 at 20:34
  • 1
    @Giorgio: I wasn't trying to say that values can be mutable. I was contrasting the adjective pure with the adjective immutable. The question asked whether we can call this function pure, and my answer was basically "no, because it isn't a function", so I was suggesting that the value could be called immutable instead. – Michael Shaw Oct 22 '16 at 1:41
3

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.

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.