Topic: Evolution of Programming – From Machine Language to OOP

Aparna SinghAparna Singh
6 min read

System Design Journey – Day 2

📆 13 May|2025

Why Do We Need OOP? A Journey Through Programming History

To understand the need for Object-Oriented Programming (OOP), we must first walk through the evolution of programming languages—starting from Machine Language, moving to Assembly, then to Procedural Programming, and finally arriving at OOP.


🧠 1. Machine Language (1st Generation Language)

How it worked: Code was written using only binary digits—0s and 1s.

Example: 000100111 – this could represent an instruction like “add two numbers.”

Interaction: Direct communication with the CPU.

Limitations:

  • Prone to errors

  • Tedious and hard to debug

  • Not scalable

  • Not human-readable

  • Hardware-dependent


⚙️ 2. Assembly Language (2nd Generation Language)

Improvement: Introduced English-like mnemonics.

Example: MOV A, 61H (moves hexadecimal value 61 into register A)

Benefits:

  • Easier to understand than binary

  • Slightly more readable and manageable

Limitations:

  • Still tightly coupled with hardware

  • Code had to be rewritten for different CPUs

  • Executed line-by-line – error-prone and not scalable

  • Lacked loops, functions, and methods


📘 3. Procedural Programming (3rd Generation Language)

Breakthrough: Introduced functions, loops, blocks, switch statements.

Example Language: C

Analogy: Like following a recipe book—a step-by-step list of instructions.

Strengths:

  • Suitable for small-scale problem-solving

  • Enabled partial code reuse

Limitations:

  • Struggled to model complex real-world scenarios

  • Separation of functions and data could cause maintenance and security issues

  • Difficult to manage and scale large systems


🚗 4. Object-Oriented Programming (OOP)

Real-World Modeling: To solve real-world problems (e.g., apps like Uber, Paytm, Zomato), we must model software after real-life entities.

Core Idea: In real life, everything is an object with:

  • Properties (Characteristics)

  • Methods (Behaviors)


🔧 Example: A Car

🧱 Without OOP (Procedural Way):

string brand;
string model;
bool isEngineOn;

void start() {}
void stop() {}
void gearShift() {}

To allow an owner to drive the car:

void drive(string brand, string model) {
    start();
    gearShift();
    accelerate();
}

But if there's another owner with a different car, you'll need to rewrite variables and functions. This approach is repetitive, hard to maintain, and not scalable.


🎯 How OOP Solves This

In OOP, we model entities using classes and objects.

OOP Approach:

class Car {
public:
    string brand;
    string model;
    bool isEngineOn;

    void start() {}
    void stop() {}
    void gearShift() {}
    void accelerate() {}
};

class Owner {
public:
    Car car;

    void drive() {
        car.start();
        car.gearShift();
        car.accelerate();
    }
};

With this structure, you can create multiple owners or cars by instantiating new objects from the same class. This makes code:

  • Reusable

  • Scalable

  • Secure (via encapsulation)

  • Easier to understand and maintain


✨ Benefits of OOP

  • Encapsulation: Bundles data with the methods that operate on it

  • Inheritance: Reuses code from parent classes

  • Polymorphism: Same method behaves differently based on the object

  • Abstraction: Hides complex logic, exposing only essential features


🔐 Abstraction (OOP Pillar 1/4)

🔍 What is Abstraction?

Abstraction means hiding internal details and exposing only essential features to the user.

Real-Life Analogy: Driving a Car
You interact with:

  • Steering Wheel (turn)

  • Accelerator (speed up)

  • Brake (stop)

  • Gear (change speed)

But you don’t need to know:

  • How the engine combusts fuel

  • How transmission works

  • How the braking system operates

Similarly, abstraction in programming hides internal complexity and exposes only the necessary interfaces.


🖥️ Abstraction in C++ (Using Virtual Functions)

#include <iostream>
using namespace std;

class Car {
public:
    virtual void start() = 0;
    virtual void accelerate() = 0;
    virtual void brake() = 0;
};

class SportsCar : public Car {
public:
    void start() override {
        cout << "SportsCar is starting with a button press...\n";
    }

    void accelerate() override {
        cout << "SportsCar is accelerating quickly!\n";
    }

    void brake() override {
        cout << "SportsCar is braking smoothly.\n";
    }
};

int main() {
    Car* myCar = new SportsCar();
    myCar->start();
    myCar->accelerate();
    myCar->brake();
    delete myCar;
    return 0;
}

Explanation:

  • Car is an abstract class with virtual methods.

  • SportsCar implements those methods.

  • main() interacts only with the abstract interface.

This is abstraction—just like driving a car without needing to understand engine mechanics.


💡 Real-Life Examples of Abstraction:

  • TV Remote: Press buttons without knowing the circuitry.

  • Phone Call: Dial a number, unaware of signal routing.

  • Google Maps: Get directions, unaware of satellite calculations.


📌 Abstraction in High-Level Languages

Languages like C++, Java, and Kotlin provide abstraction:

  • if, switch, for – you don’t handle CPU instructions.

  • try-catch – exception logic handled internally.

  • std::vector – handles memory management for you.

Even a simple line:

int a = 5;

uses abstraction—you don’t manually allocate memory.


✅ Conclusion – Abstraction

  • Hides unnecessary details

  • Shows only essential features

  • Reduces complexity

  • Makes code easier to maintain, reuse, and extend

Just like a car's interface, OOP allows you to interact through clean methods while hiding the engine’s complexity.


🧱 Encapsulation (OOP Pillar 2/4)

🔍 What is Encapsulation?

Encapsulation is the process of bundling data (characteristics) and functions (behaviors) into a single unit—a class.

Analogy: Like a medicine capsule containing different ingredients, a class wraps variables and methods together.


🚗 Real-Life Analogy (Car)

A car has:

  • Characteristics: brand, speed, fuel, odometer

  • Behaviors: start(), stop(), accelerate(), brake()

Some data (like the odometer or engine temperature) should not be changed externally—this is where data security is important.


❗ Abstraction vs Encapsulation

ConceptFocuses OnAnalogy
AbstractionHiding unnecessary detailsYou don’t need to know how the engine works
EncapsulationBundling & securing dataYou cannot directly modify the car’s odometer

🔐 Access Modifiers in C++

  • public: accessible outside the class

  • private: not accessible outside the class

  • protected: accessible within the class and its derived classes


👨‍💻 C++ Example – Encapsulation

#include <iostream>
using namespace std;

class Car {
private:
    int odometer;
    bool engineOn;

public:
    string brand;
    string model;

    Car(string b, string m) {
        brand = b;
        model = m;
        odometer = 0;
        engineOn = false;
    }

    void start() {
        engineOn = true;
        cout << brand << " " << model << " started.\n";
    }

    void drive(int distance) {
        if (!engineOn) {
            cout << "Start the car first!\n";
            return;
        }
        odometer += distance;
        cout << "Driving " << distance << " km...\n";
    }

    int getOdometer() {
        return odometer;
    }

    void stop() {
        engineOn = false;
        cout << "Car stopped.\n";
    }
};

🧾 Usage:

int main() {
    Car myCar("Toyota", "Camry");

    myCar.start();
    myCar.drive(50);
    myCar.stop();

    // myCar.odometer = 1000; ❌ — Not allowed

    cout << "Total distance driven: " << myCar.getOdometer() << " km\n";
    return 0;
}

🔎 Explanation:

  • odometer and engineOn are private—cannot be modified directly.

  • Only accessible via controlled methods like getOdometer() and drive().


✅ Conclusion – Encapsulation

  • Groups data and behaviors together

  • Controls access using access modifiers

  • Secures sensitive information

  • Prevents unintended data manipulation

Think of it as the hood of a car—everything is bundled and protected inside.


0
Subscribe to my newsletter

Read articles from Aparna Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Aparna Singh
Aparna Singh

👨‍💻 Full-stack web developer | Learning System Design 🚀 Passionate about building smart solutions & solving real-world problems 🧠 Love exploring EdTech, AI, and smart city innovations 🛠️ Hackathon enthusiast | Enjoy working on impactful, fast-paced projects 📚 Documenting my dev journey through blogs & code snippets 🎯 Aiming to become a confident tech leader & open-source contributor 🤝 Let’s connect, learn, and grow together in tech!