I heard somebody say their language has a convention where the names of functions which mutate state must end with an exclamation point. I’m trying to write more functional code and I like the idea of somehow marking functions according to their side effect status i.e. none, inward side effects, outward side effects (I’m ignorant of the right fp terminology but you get the idea I hope).
Obviously it’s easy for me to come up with my own naming scheme but I was wondering if such schemes/conventions already exist before I go and homebake one.
edit2: As for the mods closing this as primarily opinion based I have to disagree. I was asking what, if any, conventions were in common use – this is by anyone’s definition a question of fact not opinion!
Calling out methods or functions seems like a fantastic idea because it could help flush out times where code introduces a level of unsafety. Joel Spolsky delves into this idea quite a bit in his article Making Wrong Code Look Wrong (http://www.joelonsoftware.com/articles/Wrong.html) where he recommends using a less-commonly well known version of Hungarian notation to make certain ideas more transparent within the system.
The language to which you are referring is almost certainly Scheme (see http://download.plt-scheme.org/doc/html/guide/set_.html for an easy example). I am not aware of anything global.
Java prefixes property methods with
set to partially fulfill this purpose, but I am not really aware of any common conventions of the sort you mention outside the Lisp world that are not (as @gardenhead pointed out) embedded in the type system.
I think, in the main, you are pretty safe creating a style guideline for your team, particularly if you deal in something with a lot of concurrency where side-effects are even more dangerous than commonly.
For whatever it is worth, I can think of a couple of ways to implement this in ALGOL-esque languages. A simple one might be a prefix, as quasi-suggested by Spolsky – say
s_ for stateful operations and
l_ for stateless operations.
A more modern idea might be to put words as prefixes or suffixes. Maybe
calculate is a pure function but
mutateCalculation is the impure one.
Finally, there is a degree to which a lot of this should be handled by separation of concerns – only the layer that updates the database should be capable of updating the database for example. In that case, it is pretty obvious that you have to worry about side effects in stateful layers.
Follow command-query separation. Functions that return values don’t have side effects, functions that have side effects don’t return values.
It helps also to name functions that return values after the thing they return, i.e., a noun or adjective. While functions that have side-effects should be named after the effect they perform, i.e., a verb.
So for example
myArray.sort() has a side effect, it sorts the array. Therefore it doesn’t return anything and is named after a verb. Meanwhile,
myArray.sorted() returns a sorted copy of
myArray. Therefore it doesn’t have any side effects and is named after the thing it returns.
FYI, the above idea (nouns/adjectives for pure functions and verbs for side-effect producing functions) is a standard in Swift 3.
Name functions and methods according to their side-effects
- Those without side-effects should read as noun phrases.
- Those with side-effects should read as imperative verb phrases.
The fundamental problem is that side-effects are not captured in the type system. Using a function-naming convention is a poor substitute for static verification. There are a few ways around this.
Haskell uses monads to capture side-effects within a context. The monadic
bind operation composes impure functions much as the normal function composition operator composes pure functions. The monad laws ensures this operator acts analogously to regular composition.
Another route is to separate pure from impure by separating expressions from commands entirely. These are two entirely different syntactic categories that cannot be mixed. Expressions have types that allow us to compose terms. An expression, by definition, cannot depend on any assignables (it has no access to the store). Commands do not have a type in the traditional sense, and cannot return a value. They can only interact with the program by mutating the store.
Note that conventionally type-safe, “functional” languages may not follow either of these paradigms. For example, OCaml and SML do not properly differentiate pure from impure functions.
Neither of these solutions is perfect, and this is still an active area of research.