“You and ME, WE’RE JUST OBJECTS”.
We are objects – physical objects to be more specific. We take up space. Each of us has properties, such as body temperature, height, and heart rate. The things around us also take up space, have their own physical features, and can be made to interact with each other.
We can build things with these objects – think of something like a clock or a commercial airliner. These complex objects are made up of other smaller objects in a particular pattern.
In the 1960s, people who were coming up with computer languages noticed this and thought real-world objects belonged in software. Or they thought they would try and bring real-world objects into the software. As we shall soon see, the limitations that the physical world imposes would, unfortunately, tag along.
Simula, as the name implies, was made to simulate the real world with objects and was the first language to do so. At first glance, this seems sensible. After all, what could be better than modelling the world the same way that we model it in our minds?
A practical example
To illustrate, let’s simulate Sean buying something from the store. We’ll make a Sean object that will be able to enter the store, pick up things, check out, and leave. (This seems pretty simple so far.) The Sean object has properties, such as hair-colour, cash-on-hand, a cart, wants, needs, among many others.
The store object has properties too, including a list of inventory objects (each with a price), a list of employee objects (each with a wage or salary) and a location, to name a few. They both have internal and external processes. The Sean object might be able to buy, walk, run, eat, think (write a function for that!) and the like.
In addition to those, the Sean object has a vast array of internal homeostatic processes running 24/7, each existing to reach an optimal value or balanced state. Will these processes affect any other properties? To make a transaction, the store needs to keep track of and balance its inventory and cash levels. By this point, things are getting quite complicated.
In order to simulate the real world, we had to write out every pertinent aspect of the real world in software.
An even more practical example
Perhaps we should go about this in a different way? The infrastructure required to accurately depict reality in code is pretty big.
But really, all that really happens when someone goes into a store is sort-
of a flow of data, right? An amount of dollars, depending on the kind of good and quantity, flows from one thing to another.
The dollar count goes down in the Sean object and up in the store – that wouldn’t be hard to implement with objects, would it? Do we even need to make classical objects for data flows? Let’s go ahead and chose an even simpler example: shapes, each with dimensions and an area to be calculated.
Does that look like traditional OOP to you? It shouldn’t, but this should:
Even though these two code snippets do the same thing, there are some differences in approach that should jump out right away. Up top, we’re coming in at 18 lines, the shape itself is completely separate from the function that acts on it– it’s only passed into the function.
Imagine if we could do this kind of thing in real life? There would be a getSmart() function (a smartification ray gun) that would process our brains to make them smarter, and then we could, if we wanted to, make the smarts stick- make another “function” to write those changes back to our brain or even clone it – depending on how we wrote the getSmart() function (think toggle switches on our smartification ray gun).
None of this is, of course, possible unfortunate limit of the natural world. One that seems to have been inherited by the example on the bottom. If your brain didn’t have the getSmart() function while it was being constructed you’re out of luck.
But wait, we could just add the getSmart() function to the superclass and all
the other brains would get it automatically, right? We would, of course, want everyone who had a brain to have access to the getSmart() function, but what about a launchNuclearMissle() function?
A couple considerations
Some of us shouldn’t have access to that, but there doesn’t seem to be a way with this approach to selectively control who has access without making a whole new person and deleting the old one.
All of this fun inheritance stuff aside, the code is longer at 36 lines, and there is a really tight coupling between the data and its functions (methods). That became an issue in the aforementioned launchNuclearMissle() scenario, one that we couldn’t
readily solve if we write our code this way.
Applying the mindset used to write the top example, we could compose any kind of function we wanted to act on any shape we wanted it to act on. On top, we’re free to get the data from anywhere.
We can’t do that in the bottom example: a shape is both itself and what it can do – just like in real life, but nowhere near as powerful as the functional smartification ray gun we talked about earlier.
The best solution isn’t to just draw a line between Functional Programming and Object-Oriented Programming, it’s to implement coding patterns that avoid brittle code in the first place and make it easier to keep making changes, add the launchNuclearMissle() functionality just where you need it and use it on only the data you want to, instead of having everything inherit it automatically.
We know the flaws and limitations of both styles when taken to their extreme. (See this article on Functional Programming by Alvin Alexander) (See this article on Object-Oriented Programming by Charles Scalfani.)
We can’t fully model problems by only using object-oriented, everything is an object, methods – things get too complex, too quickly. Layers of functionality and attempts at encapsulation become almost intractable. Code gets brittle and unable to be extended or changed.
Likewise, we can’t reduce every problem to a functional, purely mathematical solution, as is the goal in Functional Programming. No one ideological frame of mind has a monopoly on best practices, even in software development.
With that in mind, know that this is an attempt at making sense of the complex reality we as software developers find ourselves in every day.
We can all agree that we all want to do the best work we can for those who have to read our code later: our coworkers and ourselves in the future.
If you like want to check out a related video I found after writing
this article that, you can watch it here