Computer languages can be classified by programming paradigm. This is a way of thinking about programming. It represents semantic rules of a language, that you must learn before you can read or write code.
I have encounter in practice following programming paradigms:
- Linear programming,
- Structured programming,
- Procedural programming,
- Declarative programming,
- Object oriented programming,
- Aspect oriented programming,
- Functional programming,
- Logic programming.
Some computer languages are pure and implement a single paradigm and others are hybrid and implement multiple paradigms. In my opinion, multi-paradigm languages are superior but more difficult to learn. Pure languages are more easy to implement but due to many restrictions, harder to use.
- FORTRAN is a pure structured language,
- Algol is a pure procedural language,
- Python is multi-paradigm language,
- Ruby is a pure Object Oriented language,
- Haskel is pure functional language,
- SQL is pure declarative language,
- Prolog is pure logical programming language.
In linear programming we can have a sequence of steps that can be executed one by one until the program is finished. The program has a single start point and execute all steps in the program. There is no exception, no jump and no skip. The program always has the same exact effect when is executed. For example HTML is a language that allow linear programming.
In structured programming we create a system. This kind of program is more complex. It’s effect can be different depending on user input, time, interaction with other programs, system events and so on. The idea of structured programming is that a programs can be intelligent.
Using structured programming we can create Turing complete languages. These languages can do several operations that are represented in structured programming with statements.
- Start with an initial state;
- Can ask for input;
- Can change it’s internal state;
- Can make decisions;
- Can execute one sequence of code or another;
- Can repeat a sequence of code one or many times;
- Can have one or more final states;
Depending on the computer language some are implementing sub-programs, sub-routines, procedures, functions, methods or rules that encapsulate a functionality. The main program is orchestrating the execution by translating the user input into calls using parameters or shared-states.
Sub-programs have the role “separation of concerns”. It means one sub-program does only one small thing. The main program combine the effects of multiple sub-programs to implement the end-to-end functionality of the system.
Parameters and results
Sub-routines can receive parameters and can compute results. Usually parameters for sub-routines are fixed during sub-routine execution. The result can be collected by the main program and used in next computations. Depending on the programming language the syntax of parameters and subroutine call can be different.
Parameters are similar to local variables. They are known only inside the sub-routine. Once the subroutine is finished, the value of the parameters is lost or can be propagated back to the caller. This depends on the declaration syntax and purpose of the parameter.
Arguments and values
Subprograms can receive values that are assigned to parameters. These values are sometimes called “actual parameters” other times they are called “arguments”. Important thing is that values of parameters can be: constants or variables.
If an argument is constant, you can modify parameters inside a sub-program but this has no effect over the argument. The argument remain constant. If an argument is a variable, then you have a choice to propagate changes back to caller or to protect the parameters against this secondary effect.
Output parameters are parameters that can propagate back the modified values outside of sub-program. This is a feature many languages have. It may be implemented using “pointers” or “references”. For each computer language you have to learn how to use input/output parameters.
Variable number of arguments
Lately, most languages can support a variable number of arguments using a special prefix for a parameter that accept multiple values. This symbol can be “*” or “…”, depending on the language.
When you make a sub-routine call, you can use many arguments separated by comma that will be grouped to into a collection and sent to the sub-routine. Then you can access these parameters by index and use each value.
Sometimes, parameters are optional. In this case, the call can also have a variable number of arguments but the arguments that are optional must be specified by name. You will understand these concepts better if we use an example:
#last parameter is optional
def add(a, b, c = 0, *d):
print( add(1,2) ) # 3
print( add(1,2,3) ) # 6
print( add(1,2,c = 3) ) # 6
print( add(1,2,3, 4, 5) )# 15
Namespaces and scope
When you define identifiers you must know where this identifier is visible. If an identifier is visible in all your program, it is called “global” identifier. The area of visibility is called “scope”. For example a program can have a single “global scope”.
Each sub-program usually has its own “local scope”. Sometimes in the local scope you can define nested sub-programs. Most languages will enable creation of variables and constants in local scope.
Shadowing: This is a secondary effect of most programming languages that support local scope. If you define a variable in local scope having the same name as a variable defined in outer scope the two names will collide. To avoid collision, the languages usually hide the external variable and enable access only to local variable. This effect is called “shadowing”. Parameters also have a shadowing effect over outer variables or parameters.
When you define a data structure, the elements in data structure can be public or private. If elements are public, usual notation called “dot notation”, enable you to access a member of a collection by name.
name = "Barbu"
age = 22
pass #end class
# using dot notation
print(Person.name) # Barbu
print(Person.age) # 22
Note: In previous example we define a “structure class” in Python that is also known as “data class”
The functional programming is a programming paradigm. It is a way of thinking about a function. The function is like an object. That’s the main idea. We do not create classes like in Java. We create only functions. So a functional programming language is much more simple then Java. In a functional programming language a function is “first class objects”.
Characteristics of functional programming:
- A function exist as object that can have properties and can be stored into a variable;
- We can assign the function itself to a variable, then use the variable name as a function;
- We can create a function that return other function as result. This is a higher order function;
- We can create a function that can receive as argument another function called a “call-back”;
- Pure functions do not have side-effects and return a single result.
To cope with restrictions of functional languages have invented a new terminology:
- In a functional language a function can have attributes;
- A function that is created by another function is called closure;
- Execution of a function can be suspended and then resumed;
- A function is deterministic if return exactly the same result for the same arguments;
- A function that is argument to another function is called a call-back function;
- A function that return a different value every time is called is a generator;
- A generator do not return values but yield values each time is called again.
Object Oriented Programming (OOP)
This kind of programming has introduced the idea that data and operations that can apply to data are tight connected. In pure Object Oriented programming we have only two things to define: Native data types and Classes of objects. Each class can hold several attributes and methods. The methods can change attributes.
When can use a class like a collection of methods. Also we can create multiple “instances” of the class. Each instance is called object. An object has same attributes ast the class and same methods. Except for object we can set the attribute values and change attribute values using methods.
To understand better we can compare the class with a cookie cutter. Each cookie we cut is an object created with the same template. So all the cookies are almost the same, except if we put chocolate on them and sprinkle them with different color candies. Then the cookies become a little bit different from each other.
Most important properties of Object Oriented programming:
You will find how these things work if you study Java or Ruby. Other programming languages have Object Oriented attributes: C++, Python, Rust and Go. For each language we will have a tutorial that explain in details the Object Oriented paradigm.
Mix-ins and Traits
Some computer languages that are Object Oriented enable you to inherit new features from multiple base classes. This is called multiple inheritance. Most common though, languages like Java and Ruby do not support multiple inheritance. Another way was found to enable developers reuse code.
A mix-in is a class that re-use multiple “components” to simulate multiple inheritance. The components are called “traits”, and represent namespaces. You can include multiple traits in a class to inherit all methods and variables defined in a trait. In Ruby there are no traits but modules.
Note: There are advantages and disadvantages of each programming paradigm. Therefore many computer languages implement multiple paradigms. Personally I find this a good thing.
Read next: Evolution of computer languages