I’d like to draw your attention to some of the language that we use to describe a couple concepts in functional programming, and propose a change - A change in our English language, that is. I’m going to describe some concepts that you already know if you’re a software developer, and I’m sure the familiar names for them will certainly come to your mind before I use them. First, the definitions:
Many functions are given data to work with via parameters when they’re called, but some aren’t. Similarly, many functions then return data to their callers when they exit, but some don’t. When a function isn’t making use of data that has been provided in a parameter, it’s usually making use of data from somewhere else in its calling environment - outside the function’s definition.
Various factors are involved in deciding what kind of function to write. Here’s a few:
A function that doesn’t make references to its calling environment is generally more abstract than one that does. Sometimes code is difficult to understand because it’s too abstract. And sometimes it’s hard to understand because it’s not abstract enough.
Sometimes a function that refers to its external environment is substantially simpler to understand than the equivalent logic expressed with functions that don’t make use of that environment.
Sometimes the things in the external environment referred to by a function are located far enough away or otherwise increase complexity and make it difficult to understand the function’s influence on the program as a whole.
Sometimes the indirection brought about by threading program state through parameters and return values instead of using external state can increase complexity in a different way, and decrease the understandability of the program.
Sometimes there are opportunities for optimization that are enabled by reducing a function’s interactions with its environment. But sometimes reducing those interactions are offset by an increase in the number of function invocations necessary.
Most of the time it’s very difficult to anticipate in advance which of the possible optimizations that could be made to a program really matter. The majority of the time spent in a program is in a very small portion of the code - this is both received wisdom, and my personal experience.
Now, for the terminology:
When a function doesn’t manipulate its external environment in any way, it’s traditionally called a "pure" function. To emphasize the distinction, a function that does manipulate its environment is called an "impure" function. Impure functions are said to have "side-effects," by manipulating their environment.
I’d like to propose a change in the language we use to describe these different kinds of functions. What we now call pure functions we should call plain functions. What we now call impure functions, we should call common functions. That is:
Plain functions don’t manipulate their external environment.
Common functions do.
Here’s my claim: using words like "pure" or "impure" implicitly precludes being able to easily talk about a function’s external dependencies separately from whether they’re good or not.
Because the words "pure" and "impure" carry inherent value judgments, there’s cognitive dissonance when trying to use them in sentences where the sort of function being talked about doesn’t match up with the value judgment being made about it by the sentence as a whole.
Compare the following phrases:
"It will be better to use an impure function here."
"It will be better to use a common function here."
"There’s a way to make this pure, but it won’t be as good."
"There’s a way to main this plain, but it won’t be as good."
Which are easier to say without sounding contradictory?
More importantly, how have the value judgments associated with the words "pure" and "impure" influenced what we call good code and bad code, or - more controversially, good design for a language’s base API?
In common use, when one isn’t talking about programming, the word "impure" has the synonyms "dirty" and "unclean". If you were to try describing the concepts of these different kinds of functions to a non-programmer using the traditional terms, and then come back a few days later and ask them about it, chances are likely that the words "pure" or "impure" will be associated to the kinds of functions involved by way of the value judgment. That is, a layman’s summary could be: "Programmers care about how good functions are, and they call pure functions good and impure functions bad."
I’ll even go as far as claiming that software developers do as well, especially when not talking about specific instances of code.
I’m not saying that we can’t talk independently about code’s value and its use of its environment, but that the language we’ve chosen so far makes it unnecessarily difficult. Linguistic relativism is an argument for another day.
I think plain and common are good words to use, first because they doesn’t carry as much of a value judgment, but also because they can minimize any other implicit associations that vary independently of the kind of function involved.
That said, I’m a little unsure of using the word common, but I do think plain is a really good substitute for pure. I’m open to suggestions, and interested in compiling ideas on this.
And just to head off misunderstandings and arguments about the relative merits of any given programming language, there’s a pretty wide variety of languages that I like, use, and recommend.