I feel that too much has been made of proscriptive paradigms. OOP is useful in its place. Aspects of the Functional paradigm have their strengths. All paradigms contain at least snippets of the Procedural paradigm. There are places where each is appropriate. A well written code base will include the best tool for the purpose. In these notes, I offer my own take on how best to do it all.
Just for context, I have been writing programs since 1964 as a student, for my job and finally as just a hobbyist, which is (OMG) over 60 years!. I have seen every fashion in programming come and go.
- The first programs I wrote were in Elliot803 Autocode. Almost assembler, but not quite. There were no subroutine calls only ‘goto’ and no string handling.
- Then I learned Algol60 (a fore-runner to Pascal). It was a joy to express things in my terms rather than those of the computer, but it was also weak with strings and I/O.
- In my career I was required to write
- assembler (ICL Plan),
- ICT1900 Fortran (which was nothing like present day Fortran),
- Cobol (spit!)
- C (no comment except I preferred to use the C++ compiler for the ability to prototype functions),
- VisualBasic (I ran out of letters (and ink) it was so verbose – worse than Cobol!),
- PHP (Ah the relief),
- Javascript (what an odd paradigm),
- Later, as a hobbyist I continued to use PHP and Javascript and also
- Python (in which I found it hard to handle a GUI)
Functions or objects
The functional programming paradigm requires all values to be immutable and no function to have side-effects. Clearly if a program has no side effects it is useless, so the style cannot be totally pure.
The OOP paradigm embraces state by combining data(properties) and functions(methods) into objects whose state can be changed with ease and this is expected.
So the question is, do we use OOP and bear the burden of hidden mutability or do we shoehorn our code into the functional programming style and create potentially ugly and misleading code when a side-effect is needed?
Side effects typically are needed to change the state of some external object such as persistent storage, or a peripheral device such as a GUI or a printer. These are all things. OOP objects are good at representing things. But side effects, and especially implicit ones are an easy source of programming mistakes and to be avoided.
When you want to determine a result purely from supplied parameters use a pseudo-pure function. That is, a function that at least appears pure from the outside. Internally, if it is clearer, state changes (e.g. a pointer into an array) are OK, so long as they do not persist across invocations of the function. Given the same parameters, a function should always return the same result, and definitely should not change the values of any of its parameters.
When you want to determine or change the state of something use an object. Map its state to its properties, and use methods to alter its state.
Functions should be named using verbs. Objects should be named using nouns.
Strict typing
Declaring type of a variable, parameter or return value helps catch errors prior to execution as well as during. Occasionally the type of a variable cannot be determined in advance. Use typing wherever possible, but don’t feel bound to it in every case.
Function overloading
Function overloading is when a function behaves differently depending on the type of the parameters supplied to it. e.g. (in PHP code)
function my_add($a,$b) {
switch (true) {
case (is_numeric($a)&& is_numeric($b)): return $a + $b;
case (is_string($a) && is_string($b): return $a . $b;
case (is_bool ($a) && is_bool($b): return $a || $b;
default: return null;
}
}
This makes it harder to reason about the code and harder to maintain, so if you want a function to behave in two different ways, write two different functions. Be explicit!
Global variables
Global variables hide their true character and can easily introduce errors. Since a global variable represents a state, use an object with a property reflecting the value of the variable.
Commenting code
Code that needs comments is code that is too complex. Better to make the code clear so that comments are unnecessary. Since code can be updated without updating comments, over time they can become misleading. Avoid them, except to provide metadata such as author, date, version. If comment is needed to describe the purpose of a function/method, consider if it has the right name.