Home What Exactly Are We Talking About When Talking About OOP?
Post
Cancel

What Exactly Are We Talking About When Talking About OOP?

OOP stands for Object-Oriented Programming, which is a programming paradigm based on the concept of “objects”. But OOP is more than just a paradigm; it’s a continuous process of pursuing better, more efficient, and more intuitive ways of programming. No matter if you are a novice or a seasoned expert, understanding the true essence of OOP is the key to unlocking its full potential in your programming.

Essentially, Object-oriented programming is a programming idea or programming mindset. It uses classes or objects as the basic unit for organising code, and takes the four characteristics of encapsulation, abstraction, inheritance and polymorphism as the cornerstones of code design and implementation

Design principles and ideas are more universal and important than design patterns.


Contents


Origins and Evolution of OOP

OOP didn’t just emerge out of a vacuum. It was born out of a need for managing complexity in growing software systems during the late 1960s and early 1970s. The term “object-oriented” was first coined by Alan Kay, one of the key figures behind the Smalltalk programming language, which brought OOP into the mainstream.

Simula: The Progenitor of OOP

Our story begins with Simula, which was born in the 1960s, often regarded as the first object-oriented language. In Simula, the concept of an ‘object’ was introduced to represent a real-world entity, encapsulating data and behaviour in a single entity.

Smalltalk: Bringing OOP to the Forefront

Smalltalk was originally created in the 1970s. Smalltalk took these ideas and ran with them, introducing features like inheritance, encapsulation, and polymorphism, which are the pillars of OOP as we know it today.

C++: Real prosperity for OOP

The emergence of C++ around 1980 led to the popularity of object-oriented programming and its increasing acceptance. Until today, most of the programming languages are object-oriented programming languages if not according to the strict definition, such as Java, C++, Python, C#, Ruby and so on.

In addition to this, most of the programmers do object-oriented programming based on OOP languages while developing projects.

What exactly is OOP?

  • Object-Oriented Programming (OOP) is a programming paradigm based on the concept of “objects”, which can contain data and behaviour:
    • data in the form of fields (often known as attributes)
    • behaviour in the form of procedures (often known as methods).

  • A key feature of OOP is the concept of class and object:
    • Class: A blueprint for creating objects. It defines a set of attributes and methods that the created objects will have.
    • Object: An instance of a class. It is a self-contained component that contains attributes and methods needed to make a certain type of data useful.

  • OOP revolves around four main features (or pillars, or fundamentals):
    1. Encapsulation: Encapsulating data and methods that operate on the data within one unit, like a class, and restricting access to some of the object’s components, which is a means of preventing accidental interference and misuse of the methods and data.
    2. Abstraction: Abstracting complex reality by modeling classes appropriate to the problem, and working at the most relevant level of inheritance for a particular aspect of the problem.
    3. Inheritance: Deriving new classes from existing ones, thereby inheriting fields and methods from the old classes and allowing for reuse of code.
    4. Polymorphism: Allowing methods or entities to use the same interface but behave differently based on the context, which can be achieved through method overloading or overriding.

OOP: A Mindset, Not Just a Language Feature

What is OOPL (Object-Oriented Programming Language)?

An Object-Oriented Programming (OOP) language is a programming language that supports or facilitates object-oriented programming (OOP) concepts and techniques. In OOP languages, the primary focus is on working with objects. These objects are instances of classes, which are blueprints defining the structure (attributes or properties) and capabilities (methods or functions) of the objects.

  • When we commonly talk about OOP Language, we are talking about some language that can well support the OOP concepts and techniques.
  • But this does not mean that OOP Language can only write OOP code.
    • OOP Language can write POP (Procedural-Oriented Programming) code.
    • Conversely, POP Language can also write OOP code.

How to write OOP code using POP Language (like C language)

It’s easy to write POP code using OOP Language (just expose all data and details). But how to write OOP code using POP Language? It can be a bit complicated, but it’s by no means impossible.

  • In fact, as long as you have a good understanding of OOP ideas, you can write OOP code in POP Language (like C language).
    • POP Language just doesn’t support OOP concepts and techniques well. That doesn’t mean it can’t write OOP code.

Example:

Suppose we have two types of geometric shapes: Circle and Rectangle, both of which can calculate their own areas. We will define a generic Shape structure that contains a pointer to a function that calculates the area. In this way, different types of shapes can use their own area calculation functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>

// Define the function pointer type for calculating the area
typedef double (*AreaFunc)(void*);

// Shape (Base class)
typedef struct {
    AreaFunc calculateArea; // Pointer to the function that calculates the area
} Shape;

// Circle (Derived class)
typedef struct {
    Shape shape; // Inherit Shape
    double radius;
} Circle;

// Rectangle (Derived class)
typedef struct {
    Shape shape; // Inherit Shape
    double width;
    double height;
} Rectangle;

// Function to calculate the area of a circle
double circleArea(void* self) {
    Circle* circle = (Circle*)self;
    return 3.14159 * circle->radius * circle->radius;
}

// Function to calculate the area of a rectangle
double rectangleArea(void* self) {
    Rectangle* rectangle = (Rectangle*)self;
    return rectangle->width * rectangle->height;
}

// Generic function to calculate the area of a shape
double calculateShapeArea(Shape* shape) {
    // Call the specific shape's area calculation function
    return shape->calculateArea(shape);
}

int main() {
    Circle circle = { {circleArea}, 5}; // Create a Circle object with function circleArea and radius 5
    Rectangle rectangle = { {rectangleArea}, 10, 5}; // Create a Rectangle object with function rectangleArea, width 10 and height 5

    printf("Circle Area: %f\n", calculateShapeArea((Shape*)&circle));
    printf("Rectangle Area: %f\n", calculateShapeArea((Shape*)&rectangle));

    return 0;
}

In this example, we defined a generic Shape structure that includes a pointer to a function that calculates the area. Then we defined two specific shapes structures: Circle and Rectangle, both containing a Shape structure (which simulates inheritance in C). We implemented functions to calculate the area for both circle and rectangle and set their area calculation function pointers to the respective functions when creating instances of these shapes.

Finally, we defined a calculateShapeArea function that takes a pointer of type Shape, calls that shape’s area calculation function, and returns the result. This is polymorphism achieved through function pointers, allowing us to handle different types of shapes in a generic way while maintaining their own ways of calculating areas.

  • From this, we can achieve:
    • Encapsulation: In C, it is possible to use structures to simulate “classes”, which can contain data (properties) and pointers to functions (methods). In this way, we can encapsulate data and functions that manipulate that data.
    • Inheritance: C does not support inheritance directly, but it can be simulated by structure nesting or composition. A subclass can effect inheritance by embedding the parent class’s structure in its structure. In this way, the subclass can access the properties and methods of the parent class.
    • Polymorphism: Polymorphism can be simulated by using function pointers. Function pointers can be defined in a structure, and then different functions can be assigned to these pointers so that different functions can be called at runtime as needed.
    • Abstraction: We can also implement abstraction by embedding a pointer to a common interface (i.e., a function pointer) in the structure. It allows us to hide the details of the concrete implementation and simply access the result through an interface call, thus achieving a form of abstraction.

It can be seen that while the C language can write OOP code, it is not intuitive and not easy to maintain. That’s why it can’t be called OOPL.

The True Meaning of OOP: Beyond the Buzzword

In recent years, OOP has become something of a buzzword, sometimes invoked more for its cachet than its actual principles. But at its core, OOP is about:

Modelling the Real World

OOP allows us to create models that mirror real-world complexities, making our software more intuitive and aligned with how we naturally perceive the world.

Creating Robust and Maintainable Code

With its emphasis on encapsulation and abstraction, OOP helps create code that’s not only robust against errors but also adaptable and maintainable over time.

Facilitating Collaboration and Scalability

The modular nature of OOP makes it ideal for collaborative environments and scalable for growing software needs.

OOP is a Philosophy: More Than Just a Programming Style

At its heart, OOP is a philosophy, a way of thinking about programming and even about the world. It’s about modelling the real world in a way that’s intuitive, maintainable, and adaptable.

From the emergence of OOP to its prosperity, this has meant a change not only in the way software is written, but also in the way software is perceived. OOP involves a particular way of thinking about and structuring software, drawing parallels to how philosophy seeks to understand and structure knowledge about the world.

Encapsulation: The Art of Keeping Secrets

OOP taught us the value of encapsulation: keeping the internal workings of an object hidden from the outside world. This not only prevents outside interference but also makes the code more modular and easier to manage.

Abstraction: Simplifying Complexity

Abstraction involves distilling complex reality into essential aspects relevant to the problem at hand. It enables programmers to focus on high-level operations, ignoring lower-level details, which simplifies programming and enhances code quality.

Inheritance: The Legacy of Code

Inheritance allows objects to inherit properties and behaviours from other objects, promoting code reuse and reducing redundancy. It’s akin to a child inheriting traits from their parents.

Polymorphism: Many Forms, One Interface

Polymorphism, from the Greek words meaning ‘many shapes’. It allows objects to be treated as instances of their parent class rather than their actual class. This means different objects can be accessed through the same interface, simplifying code and improving its flexibility.



Reference:

  • Wang, Zheng (2019) The Beauty of Design Patterns. Geek Time.
This post is licensed under CC BY 4.0 by the author.
ip