If you have coding experience you are certainly familiar with the imperative programming paradigm, even if you might not be aware of it. Maybe you have also heard about other programming paradigms such as functional programming. But what is a programming paradigm after all? And why do we care about the flow-based programming paradigm so much?
If you are an experienced coder you might want to skip to the flow-based section right away. But I think that it is still worth reading the other parts to make the differences clear and become concious of them.
Before we start, we want to think about one little thing: what is the purpose of programming languages? This seems like a trivial question but it really is not. The most important purpose is to allow humans to write programs that have to be executed on the computer in the end. But this clearly cannot be the only purpose since assembler code such as this would do:
msg db 'Hello, world!',0xa
len equ $ - msg
It’s the famous ‘hello world’ program that does nothing but print ‘hello world’ to the screen.
In the beginning of computer programming, you actually had to code like this. But as you can imagine, programs get very confusing very quickly. Today’s software systems could never be written or maintained if their code looked like that. The complexity and power of software systems today could only be achieved by one brilliant approach that is characteristic to the evolution of programming languages ever since: abstraction.
Abstraction is the concept of hiding unneeded details. Everyone of us uses abstraction to be even able to understand and pin down the world around us. When we see a tree, we are not interested in how many leaves it has exactly. When we see a forest, we are not interested in how many trees it has see or what trees they are exactly. When we see a beautiful landscape, a forest might be just a part of it along with a lake and an impressive mountain in the background.
Abstraction in programming is very similar. When you look at the code above it seems rediculous how many lines you
need for a trivial task like printing ‘hello world’ to the screen — and it is. For this reason higher-level
programming languages try to hide these details and offer simpler instructions such as
So this is the true task of programming languages — hide details of implementation so that you can focus on what matters, the logic of your programs to close the gap between computer language and human thinking.
Let us begin with an example of imperative programming. Famous representatives of this paradigm are Java, Python and probably most other languages that you come up with. These languages more or less directly tell your computer what to do and in which order.
a = 5
b = 3
c = a + b
It is pretty clear what happens here, isn’t it? First, we assign
b . Then, we add
b and store it in
Finally we print
c to standard output.
This, of course looks trivial and it is. The thing we want to notice here is that we can directly read the order in which these instructions are executed and what they do. Well even more: there exist explicit instructions after all. Not something that we have in every paradigm as you will see shortly.
We have just investigated one important part of imperative programming: sequencing of instructions.
Another important part are so-called unconditional and conditional jumps. They allow for conditional executing and
repetition of code sequences. You probably know them as
while loops or
while a != b:
if a > b:
a = a - b
b = b - a
This is Euclid’s algorithm calculating the greatest commin divisor (GCD) of two integers.
When you compare these examples of imperative code with the assembler code from the previous section, you will see they are easier to read and understand. But both are actually examples of imperative programming. Why is that? In the end, the code has to be executed on computer hardware. That hardware is most like a so-called Von-Neumann computer which works in a certain way. Simply speaking, it has a global memory consisting of billions of single cells and a processing unit. When we assign values to a variable, the Von-Neumann computer will write this value into a memory cell and remember what memory cell is linked with the variable. When adding two variables, the computer has to look up the variable values from these cells, calculate the sum, and write it back into another cell.
All imperative languages work like that and everything that you write (even if it is very abstract) can be mapped onto this kind of instruction set. The imperative paradigm is so popular because our computer hardware works just like that and because we can easily control it this way.
The next paradigm that we want to look at is the functional programming paradigm. You might think “Hey, I already know functions from Python.” But this is not quite the same as the functions we are talking about. Actually, we don’t want to go too deep into functional programming here, but we want to show you another example of a programming paradigm before examining the flow-based paradigm.
The functions we are interested in are functions in a mathematical sense. They cannot change the state of our program like reading from or writing to a global variable in the memory. All they can do is take the values we give them and return a value. Sounds boring, but what really makes them powerful (and confusing at the same time) is the possibility of treating functions as values. Apart from that this kind of functions has great advantages such as freedom of unintended side-effects and unpredictable behavior.
“How can a function be a value?” you might think. But what is a function after all? It is a mapping from one value
another — just like a map! And a map is… right, a piece of data and hence something that can be treated as a value.
One example would be the
map function. It takes a list of values and applies a function to each element
of that list.
int_map :: (Int -> Int) -> [Int] -> [Int]
This is the Haskell notation of a function signature. A signature is not the implementation of a function but the
types of variables it operates on. In this case,
int_map takes a function that maps
Int -> Int and a list of integers
[Int] and returns another list of
We won’t look at the implementation of map because it is not absolutely necessary for understanding the functional paradigm. If you are interested, take a look here.
Here’s an example of a sorting algorithm in Haskell:
qsort  = 
qsort (x:xs) = qsort small ++ (x : qsort large)
small = [y | y<-xs, y<=x]
large = [y | y<-xs, y>x]
Quite impressive, isn’t it? This algorithm is a fully fledged efficient quicksort algorithm. The important observation here is that you cannot directly see the instructions let alone their order that will be executed on the computer. The order of statements in functional programming is not equivalent with the order of execution on the machine. Still it works, and is much easier to read than its imperative version (honestly).
Flow-Based Programming (FBP)
Now that you have waited so long, we finally want to introduce flow-based programming to you. It is a paradigm that we believe could be used in many scenarios that are still dominated by imperative languages. The flow-based paradigm tries to have a natural way of abstracting logic and an obvious way of visualizing each of its elements.
Unlike imperative programming, FBP does not operate on a global memory. In that regard it is very similar to functional programming. But unlike functional programming, the order of its elements is important and has a meaning.
Let’s take a look at a simple example:
This FBP program takes three numbers
c and evaluates the
(a+b)*c. The elements which I was talking about are the boxes that you can see and the
connections between them.
From now on we will call these boxes operators because they are like little operating units that process
data. They take the data that comes in from their inputs and emit new data to their outputs.
* have two
inputs and one output — makes sense, doesn’t it?
Now in this case we do not really have any kind of control flow yet. All data takes the same path each time. So how can we achieve the same level of control as in imperative programming?
The Fork Operator
We need a special kind of operator for that — a fork operator as we call it.
It has two inputs and two outputs. In the example above the inputs are purple and blue and the outputs are green and red. You can imagine it as a switch with purple being the signalman. Whatever data arrives at blue will either be sent to green or red. Purple is a so-called boolean value being either true or false. Depending on whether the data arriving at purple is true (left picture) or false (right picture) the data arriving at blue is sent to the green or red output, respectively.
We can even represent loops with a similar (however slightly more complicated) approach but we don’t want to show the whole FB paradigm in all its details here. Rather, we would like to give you an impression what can be achieved with this paradigm.
Higher Level FBP
We have just seen the lowest level of FBP. You can perceive it as the FBP version of assembler. So now we want to take a look at some higher-level programs instead. You certainly remember the concept of abstraction that I explained earlier. Abstraction in FBP is achieved by packaging several operators together into one new operator. What you get is a more powerful piece of logic that you can use in your programs or share with others. The more you abstract the operators the closer you get to the software architectural view of your program. That’s right! You don’t need to grab a pencil and draw the software architecture to get an understanding how your program works — it is already there!
Let’s take a look at this example:
This is a webserver allowing users to upload images in a zip archive and have them all converted to black/white pictures. After that, they are packaged again and sent back to the user as download.
Imagine this as an imperative program… I am sure you agree the image above is understandable even for unexperienced programmers.
The cool thing about it is that each component can be used in other contexts as well. This is not always true for functions in imperative programming: they very often depend on a certain global memory states or a rely on a specific environment. FBP operators are completely independent.
We at Bitspark are currently developing a FBP language called Slang. Slang stands for stream language and aims to be a full-blown visual flow-based programming language — from the very top to the very bottom. Its users shall be empowered to program completely visually without the need to write a single line of code.
Still, Slang wants to be as universal as possible. We are aware of the fact that FBP is not the solution to all problems. But we believe that the FB paradigm could be used in many, many scenarios that are currently still dominated by imperative programming and perform the tasks easier, clearer and quicker than current solutions.
Stay tuned, we will go much more into detail in future posts.