Paradigm shift
A short story from the perspective of a C++ developer
In the beginning…
The year was 1972. Dennis Ritchie, an American computer scientist, created C programming language, the most prominent imperative programming language of today. It was designed to provide constructs that map efficiently to machine instructions. With portability in mind, it was a relief that you can write portable code which can be successfully compiled and run on various computer platforms.
The old world wasn’t sleeping. Almost decade before the first appearance of C, Simula (“Simulation language”) was created at Norwegian Computing Center in Oslo, by Ole-Johan Dahl and Kristen Nygaard. Simula is considered the first object-oriented (OO) programming language.
It will turn out that C and Simula had major influence on today’s most popular programming languages.
We all know that computers are good in doing calculations and, unlike humans, they usually do it much faster. So, if we wanted to add two numbers, we would load the first number into one of the CPU’s registers, instruct CPU to add the other number, and then copy the content of the register into the result. Simple as that. Or is it? Well, by that time, having C in your toolbox, you were saved from reading countless pages of documentation for every CPU you planned to use. Life is good.
On the other hand, calculating sum of two numbers isn’t much of a task. If you want to represent more complex entities, you could use classes, subclasses, inheritance and all other goodies originating from OO programming. Aside from the data representation, a lot of computations make use of loops, control flow structures, etc.
Remember the “goto”?
Vast majority of imperative programming languages have a goto statement which performs one-way transfer of control to another line of code. Of course, today everybody knows that using goto statement is plain wrong thing to do because it creates “spaghetti” code and it’s proven that it’s not a necessary statement to write programs. Also, probably the most famous criticism comes from the 1968 letter of Edsger Dijkstra called “Go to statement considered harmful”.
This is a classic example how something that was considered natural at some point (e.g. assembly language with goto a.k.a. unconditional jumps ) gets considered harmful, and for a good reason.
Goto statement is not a lonely case. Software development evolves and transition to the new paradigms and way of thinking should follow that accordingly.
Birth of C++ and the evolution (until 2003)
In 1979 Bjarne Stroustrup created “C with classes” and it was meant to be an extension of the C language. Bjarne wanted to inherit C’s ability to manipulate memory on the low level, and at the same time the ability to create more complex entities (i.e. objects with data fields and methods). In “C with classes” you could combine procedural and OO programming paradigms, while still having the low level access to the memory.
And here is the timeline of important events for the evolution of C++:
1983 – “C with classes” was renamed to C++. The subsequent releases (C++ 2.0 in 1989, C++ 2.0 update in 1990) added new features like abstract classes, multiple inheritance, protected members, exceptions, etc.
1991 – The release 3.0 introduced templates, a mechanism which enabled generic programming paradigm.
1998 – C++ is standardized by ISO working group for the first time.
2003 – Bugfix release, which was mainly focused on fixing issues identified in C++98
A whole new world
At the beginning of 21st century, Java and .NET became the most popular technologies in the industry and we entered the era of rapid application development. Suddenly, all the memory issues disappeared with the advent of Garbage Collector (GC). GC will eventually clean up all the memory of unused objects. The question is whether “eventually” is soon enough for you when it comes to resources like sockets, database connections, etc.
OOP design was a getaway ticket for every majority of architectures. If you don’t know where to add additional functionality, just create a class, wrap some data and pretend that it’s encapsulated (i.e., the immediate and unexplained urge to generate getters and setters for all the data within a class was effectively flushing the encapsulation down the toilet).
Also, value semantics was put aside and everything ended up on the heap (except maybe primitive types). Designing a good class hierarchy is not an easy task and subtyping is not so trivial as it looks like.
A function that has large number of arguments usually indicates a code smell. But somehow defining yet another data member within a class is just fine. IMO, that’s also a code smell and it should be avoided whenever possible. Defining new data member expands the current state of the object and the more unattended states, more bugs and undefined behaviours.
In the recent years, outside of academia, functional programming paradigm (FP) became more visible then it’s used to be. Procedural and OO programming paradigms are both imperative and FP is a declarative one. In a nutshell, FP is focused on defining what should be done, and not how. FP avoids changing states and mutable data in general, encourages usage of pure functions (functions with no side effects). Without shared states, one can increase performance of concurrent and parallel processing dramatically.
C++ renaissance
Coined by Herb Sutter in 2011, the term “C++ renaissance” announced new C++ era, or what it is widely known today as Modern C++ . After 2003, the next major C++ revision was referred to as C++0x but it was not released until 2011, formally known as C++11 . New features were r-value references, move constructors, constant expressions (constexpr), type inference, uniform initialization, range-based for loops, lambda functions and expressions, etc. It felt like a new language indeed, and most importantly, we don’t need to wait ten years for the new releases. C++ Standardization committee entered the three-years cycle and now we have C++14 , C++17 and feature complete C++20 revision (not yet released).
This is how ISO WG21 – C++ committee looks like today:
One of the important Study Groups is SG20, with an aim to produce guidance for modern course materials for C++ education.
There is no accident in emergence of SG20. One of the drawbacks of a long period of time without new major revision is that C++ is still perceived as “C with classes” where you must manually take care of every resource allocation/deallocation and deal with pointer arithmetics. Part of the reasons for this kind of perception is hidden in the human nature. When you move to other technology, it’s easier to continue with the same programming style, patterns and mindset in general.
And here is the list of paradigms that C++ supports:
- Procedural
- Object oriented
- Generic
- Metaprogramming¹
- Functional²
In the end…
The main conclusion is that paradigm shift (as in real life) is a good exercise, and we should get outside of our comfort zone whenever possible. You’ll be surprised how many things that we use and take for granted are the actual “ goto statements” of today.
¹ Discovered by accident. Regarding template metaprogramming, the 2001 book by Andrei Alexandrescu, “Modern C++ design”, is the first and probably most famous resource.
² Functional paradigm is formally introduced with C++11 lambda expressions and functions as first class citizens .