The Object Oriented Paradigm; Classes and Objects
Notions About Programming Paradigms
Since the invention of computing machines, the struggle for performance and technological advance has been fought on two fronts: on one hand by improving hardware performance by increasing clock frequency, the number of cores, the size of available physical memory and the complexity of the instruction set, and on the other hand, by finding new methods for efficiently programming the algorithms. By new methods we don't only mean new programming languages, although, if we follow their evolution over time, we will see a significant increase, in both numbers and variety. Why are new programming languages still being created, if there already is such a large number of them? There are several reasons, but the main one is that new functionality appears and it needs to be expressed in ways that we don't yet have (for example, SIMD - Single Instruction Multiple Data - accelerators are difficult to use in the C, because the language does not have support for vector data types). However, new programming languages are also triggered by something else: the invention of new programming paradigms.
The programming paradigm refers to the way an algorithm is described. Surely, by description, we don't mean the way the additions or multiplications are done, or the language itself, but a higher level. For example, how the data is structured, how this structures and the program behavior interacts, and so on. There is a relatively small number of programming paradigms, and we will name some examples, but it is important to note that it can't be stated that one is better than the other, but, just like in the case of programming languages, each is optimal for a certain class of applications.
Imperative Procedural Programming
Imperative programming describes an algorithm at an instruction level, which modifies the state of the program. Procedural programming structures these instructions into distinct sequences, called procedures or functions (not to be confused with functional programming), which work with global data structures, which are visible to all procedures, or local data structures, only visible to the procedure in which they are declared. As an example of a procedural programming language, we have the original C language (not C++). Programs written in C are built of functions (which can take arguments, compute and return data) and global data.
Procedural programming is being used extensively for low level programming (kernel, operating system, embedded, etc.), because C offers absolute control over the hardware resources and it maps very well to the way the processor executes the program. On the other hand, for high level applications, like text editors, client-server applications, simulators, synthesis software, etc., there a humongous quantity of code is written, the fact that procedural programming does not offer proper support for data structuring and encapsulation, makes it really difficult to use. In these cases, issues arise: security, memory allocation, maintenance and development, etc.
Functional Programming
Functional programming refers to the style and programming languages where computation is treated by evaluating mathematical expressions. As opposed to imperative programming, where we have state and variables, functional programming is based on a formal system called lambda calculus, which describes a program by composing mathematical functions.
One of the first functional languages is Lisp.
Object Oriented Programming
Object oriented programming is somewhat derived from procedural programming, in the sense that it's based on internal state and variables, but also introduces concepts that help to structure programs and data:
- classes and objects
- encapsulation
- polymorphism
- inheritance
Most of these notions will be presented in the section Advanced Notions About Object Oriented Programming.
The idea that stands at the base of object oriented programming, is that every system that performs a task, either real or software, is made of objects. Take for example a home theater system: it is made of a TV, a media box, some speakers, a remote control, some DVD and BluRay disks, a network interface, and all these objects interact with each other in order to perform the task. Now think about the DVD disks. There are multiple disks (objects), but all of them share the same properties and they function similarly, meaning that they are in fact contained in the same class of objects. This is exactly what a class and an object is, in object oriented programming. Let's try another approach!
Data Types
C struct
Starting from the C language, we recall that it provides us with a set of primitive types, included in the language standard. As an example, we have: int, char, double, etc. Furthermore, we can create composite structures, by using the keyword struct. A structure in C is composed of one ore more variables which may be of a primitive type, or another structure.
Next, we have an example of C structures definitions:
struct string{
char* str;
unsigned length;
};
struct person{
struct string *first_name;
struct string *last_name;
unsigned age;
float height;
float weight;
};
We can see that structure person contains pointers to two structures of type string. The relationship is described by the following diagram (with value examples for primitive types):
Next, we will give an example of using these structures:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
//make a default string with no content and length = 30
struct string * some_string = (struct string*)malloc(sizeof(struct string));
unsigned default_length = 30;
some_string->length = default_length;
some_string->str = (char*)malloc(default_length * sizeof(char));
strcpy(some_string->str, "Vasile");
//make a person structure in which all strings refer to the default empty string
struct person* new_person = (struct person*)malloc(sizeof(struct person));
new_person->first_name = some_string;
new_person->last_name = some_string;
new_person->age = 29;
new_person->height = (float)1.7;
new_person->weight = 68.9F;
printf("The person's name is %s %s, age %d years old, height %f and weight %f\n", new_person->first_name->str,
new_person->last_name->str,
new_person->age,
new_person->height,
new_person->weight);
return 0;
}
In this example, the diagram is different from an essential point of view: both pointers of type string refer the the same address, the same string respectively. Therefore, if new_person->first_name is changed, then automatically new_person->last_name is changed as well (in fact, it is the same structure).
To sum up, the structure, in C, is a data type composed of primitive variables or other structures. Similar to other data types, variables of the structure type can be defined, just like defining primitive type variables. The fundamental limitation of structures is that they can only hold data and not functions. This is how the class came to be.
Class and Object