A Short Analysis on The Paradigms of Programming Languages

A short look at the existential views from the language's perspective, and how they might affect our thinking and our language choices

Usually when people discuss a Programming Language’s “Paradigm”, they’re discussing whether it is Object Oriented Programming (OOP), Functional Programming, Procedural Programming, etc. To effectively communicate, let’s define what “paradigm” will mean in this post.

Paradigm: In science and philosophy, a paradigm is a distinct set of concepts or thought patterns, including theories, research methods, postulates, standards, etc, that make up existential views. Essentially, it’s a thought process based on your existential views, and it determines how you see things, define them and make sense of the world.

Let’s also define “existential”.
Existential: Existentialism is a form of philosophical inquiry that explores the characteristics of existence. An existential view is how you view existence itself. Changing just one part of an existential view will result in a change in how you view the Universe itself.

This post is not about listing every programming language paradigm and going over their similarities and differences. Rather, this post is about looking at a few paradigms, examining how these paradigms illustrate the existential views of the language itself, and examining how these paradigms influence our thinking. Some programmers prefer certain languages, not for technical reasons, but because of reasons relating to the languages paradigm. The language just “fits” them. Paradigms in programming languages also influence our thinking and our existential views. By learning more than one paradigm we become able to see things in different ways.

These nuances and differences don’t interest everyone, but they do interest me, and I hope you find them interesting too.

We’ll be using some code as examples!

The Paradigm of Data Types

Data types are one of the key foundational pieces that make up a language’s paradigm. They categorize data and distinguish it from other forms of data. Let’s compare data types in Perl and Python for example.

Python has 4 primitive data types:

  1. Strings ( “hello”, ‘a’, “5” )

  2. Integers ( 100, 42, 5 )

  3. Floats ( 10.14, 3.14, 5.0 )

  4. Booleans ( True, False )

To illustrate this paradigm in the Python programming language, “5”, 5.0, and 5 are all different data types. “5” is a string, 5.0 is a float, and 5 is an integer. You can prove this by using the built in type() function in a python interpreter like iPython (or the regular interpreter will work).

(Please note the In[x]: and Out[x]: is from iPython’s interpreter, and is not code, all the code comes after)

In [1]: type(5)
Out[1]: int

In [2]: type("5")
Out[2]: str

In [3]: type(5.0)
Out[3]: float

Compare this to a programming language like Perl, and we see a different paradigm on data types. Perl has 3 primitive data types:

  1. Scalars ( “strings”, 5, and references ( $scalarref = \$foo; ) )

  2. Arrays ( @array = (1, 2); )

  3. Hashes ( %hash = ( "1" => "Davy Jones" ); )

In Perl, many things can be a “scalar”. A string like “5” is a scalar, 5.0 is a scalar, 5 is a scalar. Perl’s paradigm does not differentiate these pieces of data the same way Python does. In Perl’s eyes, these are the same datat ype.

There is nothing “wrong” with this, but it shows a drastically different way of thinking from a language like Python. Python is much more pedantic about what type a piece of data is than Perl. To prove this, let’s use Perl’s built in ref() function on some variables to illustrate how Perl views data types.

I’m using the Perl interpreter that is built into GNU/Linux. You can access this interpreter by typing this into a terminal:

perl -de 0

Let’s begin. (Please note the DB<1> is from input in the terminal, and is not actual code, all the code is after DB<x>)

DB<1> use strict; use warnings;

  DB<2> $string = "a series of chars";

  DB<3> $int = 10;

  DB<4> %hash   = ( "1" => "Davy Jones" );

  # When using the ref() function in Perl, we have to
  # reference the variable with a \.
  # So, \$scalar is a reference to $scalar

  DB<5> print( ref( \$string ) );
  # output SCALAR

  DB<6> print( ref( \$int ) );
  # output SCALAR 
  # (notice that Perl sees an int and a string as the same)

  DB<12> print( ref( \%hash ) );
  # output HASH 
  # (Perl does distinguish hashes from scalars)

This is not to say that Python’s or Perl’s paradigm is better.. You can write a program that accomplishes the same task in either programming language. Rather, it is being presented to show how a small detail can represent a massive change in existential views from the paradigms.

You could compare paradigms of other different programming languages as well, but we’ll just focus on Perl and Python in this illustration.

The Paradigm of Iteration

Another place we see differences in paradigm is by iteration. We’ll compare iterations with three programming languages in this illustration, Python, Perl, and C.

I think iteration is one of the areas where Perl really shines, and hopefully, after this illustration, you’ll see why! Here’s the code we’ll enter into the Perl interpreter. We’ll define three arrays and then iterate over each of them.

  DB<1> @a1 = (1,2,3);

  DB<2> @a2 = (4,5,6);

  DB<3> @a3 = (7,8,9);

  DB<4> for $_(@a1, @a2, @a3) { print($_) };
  # 123456789

The equivalent of an array in Perl is a list in Python. Now, Python has ways to iterate over multiple lists like Perl does with things like *args, but that wouldn’t be the “equivalent” in Python’s paradigm. Python has a completely different paradigm, let’s write some code to illustrate.

In [1]: a1 = [1,2,3]

In [2]: a2 = [4,5,6]

In [3]: a3 = [7,8,9]

In [4]: for each in [ a1, a2, a3 ]:
   ...:     print(each)
   ...:
# output is... 
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

As you can see, Python printed out the 3 lists rather than the variables in each list one by one. We would get the same result if we changed the brackets to parenthesis or removed them entirely. Observe.

In [5]: for each in  a1, a2, a3 :
   ...:     print(each)
   ...: 
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

In [6]: for each in  (a1, a2, a3) :
   ...:     print(each)
   ...: 
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

Again, we COULD make a function in Python using *args to iterate over each list and give us the same output as Perl, but that is not the equivalent code to represent the paradigm. See, this is why I think Perl’s shines in iterations with its paradigm, because to get an equivalent in paradigm code, we’d have to do this….

In [9]: for each in a1: print(each);
   ...: for each in a2: print(each);
   ...: for each in a3: print(each);
1
2
3
4
5
6
7
8
9

As you can see, this is very tedious, and with Python’s paradigm, you would have to iterate over each list individually, rather than include them in a single statement. You’ll discover this if you write a function with *args.

In [12]: def iterate(*args):
    ...:     for each in args:
    ...:         for e in each:
    ...:             print(e)
    ...: 
    ...: 

In [13]: iterate(a1, a2, a3)
1
2
3
4
5
6
7
8
9

So even though both Perl and Python have “for” loops for iteration, their paradigm with these for loops is completely different. But these two examples don’t represent all the different paradigms in regards to iteration. For example, C has a completely different paradigm. Let’s illustrate this with some code.

#include <stdio.h>

// Anything after // is a comment
// Let's print numbers from 1 to 10
int main() {
  int iteration;

  for (iteration = 1; iteration < 11; ++iteration)
  {
    printf("%d ", iteration);
  }
  return 0;
}

// output is:
// 1 2 3 4 5 6 7 8 9 10

A language like C doesn’t have a “for each in iterable” paradigm. C has a completely different paradigm where you must initialize a start value, have a while conditional, and then an operation.

Hopefully with these examples you’re now more familiar with what I’m talking about when I talk about programming language paradigms and how a language thinks differently.

The Paradigm of Assignment

Programming languages have different existential views in assignment as well. In assignments, there are explicit and implicit assignments. Python is implicit, which means you assign data to a variable name and Python figures out what it is. To define an integer in Python you can simply say:

integer = 6

And boom, you’re done with it. You don’t have to declare what data type the data is because Python already knows due to its implicit paradigm. Other languages that have an explicit assignment paradigm, you can’t do this. You have to first declare what data type a variable is and then assign its respective data type value to it. So for example, the following code in C will give an error.

#include <stdio.h>

int main() {

  // notice no declaration of data type
  // this code will give an error
  i = 5;
  printf("%d", i);

  return 0;
}

If you try to work with this code, you’ll get something like the following:

gcc /tmp/ezyISLlADo.c -lm
/tmp/ezyISLlADo.c: In function 'main':
/tmp/ezyISLlADo.c:6:1: error: 'i' undeclared (first use in this function)
    6 | i = 5;
      | ^
/tmp/ezyISLlADo.c:6:1: note: each undeclared identifier is reported only once for each function it appears in

If you declare the data type and then try to compile it, it will be fine.

#include <stdio.h>

int main() {

  // notice the declaration of int
  int i = 5;
  printf("%d", i);

  return 0;
}

Differences in paradigm for variable assignment go even further. For example, some languages have a paradigm of assigning a variable to be constant. This concept doesn’t exist in languages like Python. All variables in Python by default are mutable, meaning they can be changed. In a language like Rust, variables are immutable by default and therefore constants. You have to declare variables to be mutable in a language like Rust.

fn main() {

    // notice the mut keyword
    // this declares a variable to be mutable

    let mut x = 5;

    println!("The value of x is: {x}");
    x = 6;
    println!("The value of x is: {x}");
}

Even then, this doesn’t cover all the differences in programming language’s paradigms with assignment. We won’t cover all of them but let’s go over two more differences.

In a language like Java there is a concept of “public”, “private” and “protected” variables. These labels handle how variables can be accessed. This concept doesn’t exist in a language like Python.

Another difference is multiple assignments. In Python and other languages, you can do something like this:

x = y = 5

In a language like Rust, you can’t do this, you’ll get an error, and once again this is due to the paradigm of the programming language.

Conclusion

So that’s a short review on programming language’s paradigms when looking at data types, iteration, and assignments. Hopefully you’ll understand how broad of a subject this is and find it interesting. We’ve only scratched the surface on three areas, there’s more to explore within these areas, even there are other areas we haven’t covered!

I think it’s interesting to think how paradigms in languages affect our thinking. Some people prefer certain languages over others and I don’t think it’s just syntax, I think some languages better fit a programmers builtin paradigm within their mind than others. I’ve studied this for a few years now and I’m fascinated with it.

If you enjoyed this, would like more content on this, or have any suggestions/corrections, let me know!