History and evolution of programming languages

Imperative Family Languages

The defining trait of imperative languages is that the programmer tells the computer “what to do”.  The imperative languages ultimately derive from the Turing machine, a theoretical construct used by Alan Turing to formally define computability. For languages in the imperative family, a line of code like “x = 1 + 2” means “take the values 1 and 2, add them, and store the result in a variable called x.”

The Turing Machine - (source: Wikipedia)

The machine operates on an infinite memory tape divided into discrete cells, each of which can hold a single symbol drawn from a finite set of symbols called the alphabet of the machine. It has a "head" that, at any point in the machine's operation, is positioned over one of these cells, and a "state" selected from a finite set of states. At each step of its operation, the head reads the symbol in its cell. Then, based on the symbol and the machine's own present state, the machine writes a symbol into the same cell, and moves the head one step to the left or the right, or halts the computation. The choice of which replacement symbol to write and which direction to move is based on a finite table that specifies what to do for each combination of the current state and the symbol that is read.

Non-Structured Programming (e.g. Assembly)

The model of the computer here is essentially a glorified calculator. Instead of pressing buttons on a calculator, data (including all button press equivalents from a real calculator: 1, 2, 3, +, -, M+, M-, etc.) are read in serially from memory.


  • add/subtract/multiply/divide floats or ints
  • Load/store data
  • (Conditionally) Jump to a place in memory
  • Stop computation


  • Mutability (instructions change the data to be the answer rather returning the answer)
  • All variables are global, since they correspond to physical locations in the processor
  • Insanely fast
  • Poor readability

Procedural/Structured Programming (FORTRAN, C, shell)

I’m grouping two concepts together since they are so similar.  Procedural programming was the idea that code should be grouped into distinct subunits (typically called routines or subroutines), while structured programming was the idea that all programs need only consist of serial statements, if statements, and loop statements.  When taken together, they form the basis of familiar, systems languages.


  • Native machine data types: Int, float, char, str, bool
  • Arrays (sometimes static, sometimes dynamic)
  • Pointers
  • If statements, for statements, while statements
  • Data structures (think JSON-style, but with fields declared at compile time)
  • Functions (which are really subroutines)
  • Importing code from other files


  • Mutability (we are free to overwrite variables, and often do so to save space)
  • Portable (the same code runs on every processor, as long as a compiler exists)
  • Really quite fast. Only hand-tuned assembly is faster.

Object Oriented Programming (SmallTalk, C++, Java, Python, JavaScript)

Object oriented programming (OOP) techniques were developed by Alan Kay in the 1960’s.  The major idea was to combine data and the functions that operate on that data into a single entity called an object.  OOP saw a dramatic rise in popularity with the advent of the Graphical User Interface (GUI), which became the predominant form of commercial software and was particularly suited for object oriented programming.  Programs in the OOP paradigm consist of objects calling one another, or the user directly interacting with them.


  • Everything from procedural/structured programming
  • Objects (a data structure that also includes functionalities called methods)
    • Instance variables (public or private)
    • Methods (functions that access or modify instance variables)
  • Classes (a recipe for making a new object)
    • Constructor function that generates a new object
    • Destructor function that destroys an object cleanly
    • Static methods & variables that are not a part of instantiated objects


  • Slower than Procedural / Structured program due to increased overhead
  • Encapsulation (internal member variables can’t be accessed directly)
  • Inheritance (extend existing code through subclassing)
  • Polymorphism (code that works for class A automatically works for all subclasses)

Declarative Family Languages

Declarative Family languages focus on telling the computer “what you want” not “how to do it”.  Declarative languages are typically closer to mathematics than computer technology, and tend to follow the lambda calculus formalism rather than the turing machine formalism.  This is OK because in the 1940’s, the Church-Turing thesis provided mathematical proof that all lambda calculable functions can be computed by a Turing machine and vice versa.  In a declarative language, a line of code like “x = 1 + 2” means “x is defined as 1 + 2.”

Lambda Calculus - (source: Wikipedia)

Lambda calculus (also written as λ-calculus) is a formal system in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution. It is a universal model of computation that can be used to simulate any Turing machine. It was introduced by the mathematician Alonzo Church in the 1930s as part of his research into the foundations of mathematics.

Lambda calculus consists of constructing lambda terms and performing reduction operations on them.

Functional Languages (e.g. Erlang, Haskell, Elixir)

Functional languages are characterized by their use of higher order functions; that is functions that accept other functions as input or return other functions as results.  This necessitates first class functions, which are variables that contain (or, “are defined as”) functions. One example of a higher order function is the map function, which takes a list of data and a function and returns a list where the function has been applied to each element in the list. The general idea of functional programming is that rather than manipulating the input data until we have the result we want, we manipulate functions until we have the function that yields the result we want given the input data.


  • Functions (in the most low-level functional languages, even numbers are defined in terms of functions!)
  • Basic types like ints, floats, strings, etc. are usually included as well
  • Recursion (it is common to use recursion in place of loop statements)
  • Linked lists rather than arrays for handling multiple data points
  • Pattern matching is often preferred in place of if statements
  • Closures (first class functions that remember their enclosing lexical scope)


  • Immutability (once x is defined as 4, x is always 4) 
  • Conceptually difficult (Haskell in particular is notorious for this)
  • Slower than comparable procedural/structured code, but can still be faster than object oriented code.
  • Expressive (using higher-level declarations means we don’t need to talk as much about implementation details)

Logic Programming Languages (e.g. Prolog)

*disclaimer: I have no actual experience with logic programming languages

Logic programming languages are based on formal logic approaches in mathematics.  These languages are designed to take a series of statements or rules and automatically find values that satisfy those rules.  For example, a sudoku solver would be easily expressible in a logic language. One highly-researched application is in Boolean Satisfiability (SAT), which is used industrially in computer hardware design.


  • Symbols
  • Predicates
  • Constraints


  • Even more conceptually challenging than functional programming
  • Describe the problem rather than describe the solution

Query languages (e.g. SQL, SMARTS (yes, the chemistry one))

Query languages are used in databases to allow the user to retrieve data.  The most common one is Structured Query Language (SQL), but many database-specific variants exist.  In general, the user declares the form of the data they want, along with some criteria, and the language runtime then interprets the request and translates it into a series of lookups that ultimately result in the correct data being returned.


  • Data (typically text)
  • Search terms
  • Functions
  • Boolean operators (AND, OR, NOT)
  • Wildcards


  • Not widely used to build large programs
  • Data is immutable (can’t be changed during a typical query)

Related Posts

Using Cyclica’s technology to identify repurposed drug candidates for COVID-19

At the time of writing this article, over 1.3 million people have been confirmed to be infected...


Demystifying Protein Structure Prediction Models: AlphaFold, RosettaFold, ESMFold and beyond

The purpose of this blog post is to provide an introduction to protein structure prediction models,...


The need for speed: how drug target discovery can drive change in precision medicine

Employee Perspective: Cyclica’s Marketing and Communications Specialist, Rebecca Woelfle