The concept of "side-causes" doesn't seem to be a very established term yet, but I think it should be, for conceptual clarity.
The current discussion in functional programming revolves very much around side-effects (and how to avoid them). I've noticed a tendency to label every undesired influence or reliance on externals as "side-effects". Which doesn't really make sense, if you think about it in terms related to our physical world (from where the concept of an 'effect' assumedly was derived, originally). In the physical world we have both causes and effects, which are clearly distinguished (albeit sadly often confused or reversed). So we'd do well to distinguish these concepts in programming as well.
The colloquial definition seems to be that side-causes are hidden inputs, and side-effects are hidden outputs.
But, with some help of our AI language model / search engine of choice (perplexity.ai), to word it more precisely and list useful examples, we can say the following.
Side-effects and side-causes are related but distinct concepts in programming:
Side Causes
A side cause refers to an implicit input or dependency that a function relies on, beyond its explicit arguments. Some examples include:
- Reading from global variables or module-level state
- Getting the current time or generating random numbers
- Reading configuration from the environment or system properties
- Calling impure functions that depend on external state
Side causes violate referential transparency, meaning you cannot simply replace a function call with its result because the result may be different each time due to implicit inputs. This makes code harder to understand, test in isolation, optimize, and run in parallel.
Side Effects
A side effect is a change in system state or observable behavior that occurs as a result of executing a function or expression, beyond just returning a value. Some examples of side effects include:
- Modifying a variable or data structure outside the function's local scope
- Writing to a file, network, or database
- Triggering an exception or error
- Calling other functions that have side effects
- Outputting data to the console or UI
Side effects make a program's behavior dependent on the order of execution and previous state, which can make code harder to reason about, test, and maintain.[1]
In summary, [explicit (my note)] side effects are about outputs/changes beyond the return value, while side causes are about implicit inputs beyond the arguments. Both can make code harder to reason about, especially in combination. Functional programming aims to minimize or isolate side effects and side causes for better modularity and determinism. [1][3]
Explicit vs Implicit Side-effects
In addition here, we can make a further distinction between two variants of side-effects. Importantly, side-causes often result in implicit side-effects. Because:
- if a function has a side-cause,
- and the side-cause changes from an invocation of the function to another,
- and the function uses it in computing its result,
then, even if the function does not affect the outside world apart from returning its result, the result is affected. This can be seen from the outside of the function (by anything that relies on its result). So even though the function didn't directly affect the outside world, through a write operation or other kind of output occurring during the function execution, it still introduced some side-effect into it's own result. This is another way to view side-effects. Side-effects can be explicit (hidden extra outputs), but also implicit (silently modified results).
I think the reason that side-causes are often erroneously called side-effects, is because side-causes generally introduce (implicit) side-effects, if the side-cause affects the function's result in any manner. (If it doesn't change the result, why is the function even relying on that side-cause in the first place?). In this case you could say that "there is an unintended side-effect/surprise when calling the function", but simultaneously that "the function does not have a direct side-effect/cause on its environment".
I hope this helped give some conceptual clarity, and can be a post to link to for distinguishing these two terms specifically.
PS: Funnily enough, it seems the AI derived its understanding from the following citations, where the only citation it used that mentioned side-causes was my own brief comment on the Software Engineering Stack Exchange site:
"read from any input stream" is strictly speaking a side-cause, not a side-effect. Writing to an output stream would be a side-effect. See: blog.jenkster.com/2015/12/what-is-functional-programming.html
Citations used by the AI:
[1] https://en.wikipedia.org/wiki/Side_effect_%28computer_science%29
[2] https://www.linkedin.com/advice/0/what-some-common-sources-side-effects-functional
[3] https://softwareengineering.stackexchange.com/questions/15269/why-are-side-effects-considered-evil-in-functional-programming
[4] https://dev.to/ruizb/side-effects-21fc
[5] https://www.freecodecamp.org/news/pure-function-vs-impure-function/
The top Google results I've found previously mentioning "side-causes" are:
- http://blog.jenkster.com/2015/12/what-is-functional-programming.html (Dec 2015)
- https://chaddha.me/understanding-the-enigma-of-rxjava-part-1-8e04a456d9de (3. Oct 2016)
- https://gist.github.com/mattclaw/554cf037cdf5d05425d738863e8cfe97 (22. Sept 2016)
- https://medium.com/go-for-marty/what-are-pure-functions-side-causes-and-side-effects-5a2a01f7cbcd (14. Nov 2017)
- https://www.skylerlemay.com/blog/2019/08/19/what-is-a-side-effect-anyway-30daysoffp-week-2 (19. Aug 2019)
- https://www.reddit.com/r/functionalprogramming/comments/15axgtp/a_concise_name_for_code_lines_without_side/ (27. Jul 2023)
Do you know of any earlier reference to "side-causes"?
Top comments (2)
Why generate random number is a side-cause? By your definition this should be a side-effect, as "generate" imply that the output is non-deterministic, thus being a side-effect, by extension depending on this function turning the client a function with side-effects too.
Good question.
It depends on how the random number is used, if it is passed into a function or generated inside of it. In my description I assumed it was generated inside the function. Then it is a hidden input to the function, akin to making an API call for a number.
It also depends on whether the random number is used within the function do do something or in a conditional, or if it is explicitly returned from the function. If it is explicitly returned, then I’d say it is more of an effect than a side-effect. Even if not deterministic. (The function’s purpose may be to give a random number within some range).
A side-effect free function doesn’t necessarily have to be deterministic / referentially transparent (can replace the function call with its output). Pure functions are often defined as functions that are both side-effect-free and referentially transparent.