The vast majority of programming languages in use today are structured languages. The structuring refers to grouping functionality together into loops, blocks of codes and subroutines in contrast with the using the “go to” statement which was used to jump to different parts of a single chain of commands. This structure improves clarity and re-usability of code.
One of the most notable features of structured programming are the subroutines, also called methods, procedures, function, etc., depending on the language but they essentially consist of subsets of instructions, grouped together to perform a specific operation in a black box like fashion: whoever uses the code only needs to know what goes in and what comes out (in terms of types), in case of functional languages and additionally how the subroutine modifies the state of the application in case of imperative language (which are the vast majority of them).
There are many paradigms of computing regarding functions (declarative, function, logical, and so on) which impose restrictions on how these subroutines should act regarding the computing environment (some change state, others are not allowed to change state only have output) but the vast majority of languages that handle data modeling (procedural programming or object oriented programming) apply the concept of the subroutine as a mixed concept. They are allowed to have, or not to have, a return value and they are also are allowed to have side effects (affect application state beyond the scope of the function and its return value). This versatility, is a compromise, which is necessary in most cases due to the complications that arise from using a strict paradigm like procedural programming does. The benefits are increased efficiencies, re-usability, but there are also drawbacks to this approach.
These functions rely almost exclusively on structure imposing very little limitations which can be detrimental when it comes to inference (use of deductive reasoning) and code automation because there are no basis on which such paradigms can be implemented. The interior of the subroutine can be as long (verbose) as the developer deems fit, can perform any number of changes to the state of the application as a whole: write to disk, network, change user interface and so on. While these are all necessary things, the fact that they are allowed to be performed all in one place is a huge handicap from the perspective of semantics.
Operations on the other hand are code snippets that usually wrap a single action. Examples of operations are the mathematical plus “+” operation, subtraction, multiplication, logical operations like greater than “>”, and so on.
Operations are often regarded as simple, semantically charged activity entities. Operations strongly wrap the concept what they stand for, the restrictions they impose on the operands (parameters) and for this reason, operator overloading has often been criticized that it allows developers to create operations that are confusing by using an operator that wraps a concept, for example the “+” sign, and implement code for it that perform a totally different concept, like adding an element to a set1. It is notable how people observed this fact and even argued against operator overload for feeling the need to preserve the semantics of the activity across code and even language. This is especially interesting because functions suffer from the same problem too, (see: Functional Confusion), yet nobody seems to be bothered by that. The reason for this bias could be a combination of computing reality and developers’ need for semantic information. Operations come from mathematics, are very strict in nature and we are taught to like that strictness because it is very reliable:
- Example 8, Result of the + operation based on the input
n + n1 = n2, for n, n1, n2 ∈ ℕ n + r = r1, for n ∈ ℕ and r, r1 ∈ ℝ
The definition domains (types) of input and output values are so compact, so simple and so strict, that there is absolutely no doubt in the formulation. It is elementary, it conserves the concept and the same way mathematical proofs can be built on it, so can automation inside a software.
The problem is that operations are few because mathematics is only concerned with a limited aspect of our reality and these operations are designed to serve that strict concern. Programming on the other hand has many and various needs outside the scope of mathematics (conceptually speaking). Adding a button to a canvas object or watching for events on the network have no mathematical counterpart. To serve these many and various needs the functions (subroutines) were developed. These functions have loose definitions to be versatile, as opposed operations but as such they lost the semantic charge and developers have learned to accept that as a fact.
- 1, One could state that adding an element to a set has similarities with the addition of number, for what the + sign stands for, but the similarities are brought in by the similarities in language. The two concepts are completely different.