Although the mathematical origin of the function concept is clear, its incorporation into a programming language can lead to several different formulations depending on what operations are allowed on variables. Different levels of restriction can be considered, leading to different concepts of function:
The second level has interesting mathematical properties that can be used for code optimization. For example, if F is such a function then for evaluation of an expression such as
F + F
the function need only be called once. However this kind of function would not be allowed to perform input-output (since this is a side- effect), and instrumentation (by update of a global counter upon each call) would not be possible.
The third level allows functions such as random number generators or memo functions, which modify the global environment. Such functions do not have the aforementioned properties. If for example RANDOM is such a function, then 2*RANDOM is not necessarily equal to RANDOM + RANDOM.
In an earlier version of Ada - the Green language - we attempted to provide a formulation of functions that corresponds to the second level, but experimenting with this concept has shown that this would exclude many benevolent side-effects. For example, it led to the imposition of limitations on access variables (since the invocation of an allocator is a kind of side-effect). Furthermore, checking for functionality could require reconsideration of the text of separately compiled compilation units.
These conceptual and implementation difficulties led to the present more pragmatic definition, which corresponds to the third level.
The only limitation imposed in Ada on functions is that the mode of all parameters must be in: it would not be logical to allow in out or out parameters for functions in a language that excludes nested assignments within an expression.
This means that optimization of expressions such as F + F will be achieved only when the compiler can conclude that there are no side- effects that matter.
For multiple calls of functions within an expression, Ada follows an approach of collaterality as described in section 3.8. This means that the language does not define in which order to call F, G, and H in an expression such as
F + G + H
The language rules state that this evaluation must be done in some order - that is, not in parallel - but this order is not defined by the language, so that the meaning of a program for which this order matters is not defined.
This semantics reflects a pragmatic view of side-effects, once expressed by Brian Higman [Hi 63]:
The plain fact of the matter is (1) that side-effects are sometimes necessary, and (2) programmers who are irresponsible enough to introduce side-effects unnecessarily will soon lose the confidence of their colleagues, and rightly so.