The next programming paradigm is due

And I’m working on one now.

Ilya Mikhaltsou
8 min readJun 17, 2018

Intro

Hello there. I assume, that coming here you already know most things I’ll be talking about, but let me still refresh some of them, in the hopes of guiding you to the same conclusions I got.

Walking the path of history

You probably heard of imperative programming, even if you haven’t heard the term. The oldest art of writing algorithms, written line by line and executed the same way. The purest form of programming. But of course there’s a catch — if you take some modern app written in a couple of days, it may take upwards a week to write it in an imperative language. And there’ll be bugs… tons of them.

No wonder, because you have zero abstraction. You have to meticulously take care of everything your program does at any point in time. And in the case of strictly imperative programming, that includes program paths at every condition, loop, or repeated task.

Add there if-else, while and other simple constructs, and you get yourself into the realm of structured programming. This way you just made the first abstraction, conditions. Now you won’t need to care about each conditional flow, and will have the ability to change your program easier and faster.

Now how is changing important? The code is never set in stone. The development is always iterative, and so you will always change the code that you wrote, be it fixing bugs, adding features, or even finding that your first version was simply wrong.

So the easier it is for you, the programmer, to change code, the faster will you write it.

And hence we venture into the next realm, procedural programming. This is where you combine repeating tasks into one generalized task, a procedure. Let’s consider how it changes the way we think. Before, you made the program by thinking about tasks singularly. For each task that you needed done, you just spelled out its solution into code. With procedures, you now think about each task as potentially reusable. You strive to write it in a generalized way, so that when you need that same task somewhere else, you know it’s already available to you. And if you find that you need it better generalized, you change it, and most probably it won’t affect the code you used it in elsewhere. That would be because when you used it, you used it without relying on how it’s written, only considering it as an abstract task doing what you intended for it. You also get the ease of fixing bugs and changing functionality — almost no need to care about how and where you used it (compared to imperative programming).

So you can see, that each next paradigm evolved the way we write programs, the way we think about them. And also, most importantly, it reduced the scope of what we need to keep in our attention while programming. The same is true for the next major paradigm, Object-Oriented programming.

This is where you introduce the concept of objects and classes. This is a fairly simple idea, introduce a way to encapsulate data with the tasks that operate on it, into classes and objects. While in procedural programming you had to lock in to a once-made data structure, now in OOP your data structure is also changeable and sealed away from the rest of your program, just like in procedural programming you sealed away tasks (procedures) to reuse them in a generalized way. You also have an added benefit of inheritance, which is another way a class may be reused when you need to specialize the way it operates. And nowadays it got changed a lot, since we have interfaces, protocols, traits, and whatever else, which are all quite useful.

Summarizing what we found

Let’s walk a back now and carefully compare what we’ve got.

  1. We started from adding control flow semantics to imperative programming, and got structured programming.
  2. We then required procedure generalization and reuse, and got procedural programming.
  3. And then we required object generalization and reuse, and got OOP.

I would also like to note here, that the last two weren’t easy on the developer. They both required a major shift in thinking to become useful. Now, this may sound like an introduction to functional programming, telling you how hard it is for a developer to adopt and how great are the benefits, but I suggest we do not rush to this bright mathematical future. Let’s first analyze some other modern paradigms.

To reconsider what we have

What paradigms that are in use in general-purpose programming languages do you know? Well, Wikipedia provides aplenty, so let’s focus on the few that are in a relatively-wide use.

If you think this article may benefit from inclusion of some other paradigms, leave a note, and I’ll be glad to include it here.

Event-driven programming. The programming model is enriched by having events, an abstraction over passing the procedure by reference. Basically, you get a simplified way to do that: subscribtion to events and firing events.

Reactive programming. The abstraction of the data-flow and data transformations in the program. Provides a way to declare pipelines of chained operations over some continuous input.

Actor model. A very useful abstraction of concurrency, where your interaction with other actors is done by message passing, and your state is only local.

Well, here’s a pattern: the few above are all akin to the changes brought to imperative programming by structured programming. They all bring a few new constructs that allow to write the program faster and more clear, but the program as a whole remains the same as it was. Comparing this to procedural programming and OOP, we can say that those are indeed major programming paradigms, and others mentioned above are supplemental.

You can note that supplemental paradigms bring quite a lot of ease into programming, and may allow us to develop software up to 2–3 times faster*. And at the same time, the level of reuse that was brought by procedural programming, and that was brought by OOP allows to develop 10 times faster.

* No, I didn’t measure.

Some long time ago, it was relatively easy to write a program that computes something and prints the output. Some less time ago, it was relatively easy to write an OS kernel, a console GUI application, or even a (now considered simple) game. And some very little time ago, a single developer can create beautiful and feature-rich smartphone apps. So how easy it is to make a Super Mario now? Write an OS kernel? And writing apps is also easier. But so has diminished the utility of the programs of the previous generation.

At the time when imperative programming was dominant, a software that could output data structured visually in a table was quite useful. To write it, some good effort had to be made, and that could’ve been an actual selling point of some software.

And now, is that even remotely relevant? How much time and effort would it take to add output in a table? So the utility is obviously less. Writing your own OS kernel now has also almost zero utility. And a lot more.

So where does functional programming stand? Well, I wouldn’t say there is a definite answer to that. In my opinion, that would be a supplemental paradigm gone wrong. It truly has merit as a supplement to any major paradigm, but if you consider it as a major paradigm in itself, the level of abstraction you achieve hardly brings utility. Maybe just it came too late, and every piece of software that could’ve been done in FP has already been done in OOP plus some supplemental paradigms.

And think of what comes next

And what does come next?

One thing that does is much more of client-server interaction. It is no longer a realm of big apps, and simple web apps also start to lose their utility. But writing them is still a pain, that takes a sizable team and a lot of effort. Writing another Google Calendar? How much time will it take? Will it be significantly simpler than it was initially for Google? Not so much.

Another is having more of AI. And we don’t even have a reasonable platform for incorporating AI. However we write it today, most of it will still be either a cascading if-else, or a DSL with the model. Most modern AI frameworks prefer DSL.

Distributed computation is another. Each app has problems when it requires to be split across multiple computation nodes, and designing one around it is also a huge effort to take.

A “Notes” app is a commodity, yet it isn’t that easy now to develop, when users consider cross-platform sync, document scanning, format conversions, live note sharing — basic features.

So when the expectations of users and the capabilities of developers mismatch so much, we are already at the point where the next paradigm is due.

To have a chance at the future

That is what I thought, when I started working on Genetic System Architecture (not saying the name is great, maybe gene programming is better?..)

What is it, how it works and how to use it — I’ll dedicate a separate article to that.

Here I am going to tell you what it’s for, and I just told you why.

What it gives, is a new generalization, of the task flow itself. The condition of the task execution is also a part of an encapsulated and generalized “Gene”. While it is not dissimilar to declarative languages, it is important to note a major distinction from the family of declarative languages: it is not declarative. Though the genes need not be called explicitly, the program flow and data flow are quite explicit. Much like OOP, it is based on imperative programming, and naturally interfaces with it. In this paradigm, if a developer properly generalizes the condition-task blocks (genes), then whole features may be added, replaced or thrown away without touching anything else. This shift also removes the boundary of execution, so that it doesn’t matter how genes are split between computational units (e.g. client-server, or distributed). And that’s the gist of it.

There is a lot more to know about GeSA, but let’s leave it for another article. Right now, I continue working on the following GeSA projects:

  • Microgene-Swift. A PoC implementation of Genetic System Architecture. (v0.1)
  • GeSA-Swift. Implementation of GeSA on Microgene-Swift. Intended to be a full implementation later. (not done yet, but has a quite good explainer on GeSA, though incomplete)
  • Microgene-py. An implementation in C++ employing Python for writing genes. (in progress, closed source for now)

I do not intend this post to be an ad for GeSA, but rather to highlight the problem we have with software development, and a potential path forward. There may be many other paths to major paradigms; but most certainly I believe that just developing multitudes of programming languages, as is done now, will not help, unless we have a new paradigm,

and it is due now.

Stay tuned for the explainer on GeSA, discuss other paradigms, or tell me whatever you think about any and all of it :)

--

--

Ilya Mikhaltsou

Never will know what I’m doing But will be doing it nonetheless. Oh, and you can find my info on https://morphe.by