Classes vs "free data" + functions
The freedom of data is always at the expense of the freedom of the programmer:
- With a POD you're free to do whatever you want. And what you want, you will implement in a nicely overloaded function.
- But other programmers (or your future yourself) are also free to do whatever they want and express their creativity. They are free to shoot themselves in the foot if they don't pay close attention to what they do.
- In addition, as soon as you expose a POD publicly, it's no more a freedom: it's an instant technical debt! Why because you have no longer control on how the data is used, so you have no longer the power to change the structure as you want (e.g. if you'd decide to replace integer day, month, year with a single date field). Changes would require careful analysis of all the code using this data.
- In small systems with a couple of programmers you can impose some discipline which mitigate these risks. However in programming at the large (spacecraft engines, nuclear powerplants, telecommunication systems), with thousands of programmers, such visibility will inevitably cause bugs, or undesired dependencies that hamper future maintenability. It's statistical.
This is why so many efforts were undertaken in programming languages to control of visibility of data and functions has been an issue in large systems, since the early days of structured programming:
- In pre-object oriented world, this lead to Simula's concept of module that was developped further in languages like Modula2 or ADA.
- In the more recent object oriented languages, this lead to the conept of class. THe class let you by the way the liery to create and manage multiple instances very easily whereas in modules you don't have this facitility.
What I try to say above is that the discipline of classes give you more freedom than you think. It's just a question of point of view (i.e. the owner of the class vs. the consumer).
What classes can do more
As you've mentioned, classes can do more than free data with functions:
- encapsulation and separation of concerns
- data abstraction
- inheritance going from a general class to more specific ones
- polymorphism, allowing invocation of functions/methods that are specific to a class without knowing at compile time which class the object will be
Classes are also a building bloc for additional freedoms:
- We witnessed in leading languages the emergence of generic programming, which allows you to defined a generic function independently of the data that it has to manipulate.
- The concept of design patterns also was a breakthrough. It's difficult to imagine such patterns implemented with POD and functions. (In fact I can imagine, because I did for years in a non-object oriented language: it works but with which complexity...)
Conclusion
As conclusion, a quote from Bjarne Stroustrup:
Do we really need multiple inheritance? Not really. We can do without multiple inheritance by using
workarounds, exactly as we can do without single inheritance by using
workarounds. We can even do without classes by using workarounds.
(...) The reason languages provide
inheritance (...) is that language-supported inheritance is typically
superior to workarounds (e.g. use of forwarding functions to
sub-objects or separately allocated objects) for ease of programming,
for detecting logical problems, for maintainability, and often for
performance.