Sunday, 22 July 2018

Functional, Imperative, Declarative, Monads, Abstraction, Decoupling, Dependencies... Delegation

A lot is written about all these things but there is just one goal: delegation.

A block of code will often do many things and have many effects and side effects including raising exceptions. This means the code becomes deeply embedded in the life of the program having links to many things... and the spaghetti starts making future changes, debugging and general understanding of the code exponentially harder as the program grows.

The goal of beautiful code is to create units which can be isolated, unplugged and replaced from the program easily. This means in the future, understanding what the unit does, debugging and changing it become a matter as simple as unplugging a light bulb regardless how massive the parent program is.

And this is achieved by delegation. In other words the unit does only what it is required to do and can leave all other details to the outside world. The USB socket being a great example: by abstracting serial communication the hardware of plugging devices into computers has been completely separated from what those devices are.

In React programming for example the issues of actually generating a page are left (delegated) to the rendering engine. All the individual units have to do is work out how they should look, but they never do any actually page building in real time... perhaps the engine won't ever need them... they don't need to care about events and the world of real world display any more than the engine of an HTML page has to worry about the details of internet packet transport.

Delegation is usually used to refer to dependency injection and typed wrappers for function pointers... but it is the same thing. When we encounter a delegate in this sense we can ignore what the delegate actually is in the "real" live world we just know what it should be by the function (type) definition. It is up to the user of our code to supply the actual delegate code, so we have delegated all responsibility to them... we can forget about it.

Encapsulation in OO is the same in reverse. Users of our objects can ignore the implementation, they can delegate those worries to us, exactly as how our objects are used we don't care about either... whether they never even get compiled into a final program or whether they end up controlling a space craft.

Functional programming is the same... a piece of code does one thing that is well defined.. the function user can delegate all responsibility to the function writer, all they know is that the function will transform their data in one way and one way only with no side effects.

In all these ways a block of code does just one thing, completely ignoring its context, and completely independent from its single (if possible) dependency... delegating in both directions all responsibility apart from what it is supposed to do.

By transforming* programs into indivisible units which do just one thing (single responsibility principle) and exporting all other worries to other units, layers and platforms we create easily maintainable and usable code.

*Transforming programs may not be one dimensional. For a contrived example we need to calculate the standard deviation of a set of numbers and also the magnitude. Both these require summing the squares of the numbers. We don't know for sure what the best way of summing squares is so in each implementation we delegate to another function and let that worry about the problem. This would be simple one dimensional refactoring. More sophisticated might be delegating all maths operations to a whole math layer which interprets math strings. So we transform our problem from calling a chain of functions on a data set to building strings which we export to something like Mathematica or R. "x={data set};magnitude(x)" has completely transformed the problem for a different environment. Consider how easy to change the strings for the Mathematica environment compared with actually changing the function chain.

Declarative and Imperative seem to me to be a spectrum. Everything is imperative to some extent unless writing in machine code. An imperative programming language like C is actually a declarative language for a compiler which will make optimisations and may not implement the machine code like the programmer intended at all. At the other end even Mathematica, a functional language, still requires a sequence of functions (or instructions) to be performed on the data, and while those instructions don't need to worry about loops and byte by byte operations they still instruct the engine to do this. Perhaps a lot of the confusion in these terms is that they are not entirely distinct.

Done it: proof that Jewish thinking is limited. Spent most of the day avoiding triggering ChatGPT but it got there.

So previously I was accused of Anti-Semitism but done carefully ChatGPT will go there. The point in simple terms is that being a Jew binds y...