← Back to list

The Final Frontier: Object-Oriented Data Abstraction Theory

I do not know how to explain this fully yet, but it will definitely be evident in every single project I write in C from this day forward.

Ohimai · 2026-08-06 15:48 · 0 claps · 3.9 min read
#sicp #computer-programming #c-programming
Open on Medium ↗
Wiki topics: TLS · Design Tools & Workflow CRY · Crypto & Web3 💻 · Programming

The Final Frontier: Object-Oriented Data Abstraction Theory

I do not know how to explain this fully yet, but it will definitely be evident in every single project I write in C from this day forward.

When people say, “Make a function simple and do one thing,” I have always thought about it this way: “If you want to update and rename X, create the update function and the rename function separately and call each.”

Even writing that right now, my sixth sense tells me I am right. But SICP did something to me — specifically in Chapter 2.4: Multiple Representations for Abstract Data. They dropped this line:

“We have introduced data abstraction, a methodology for structuring systems in such a way that much of a program can be specified independent of the choices involved in implementing the data objects that the program manipulates.”

For some weird reason, I sat down with that. What did they mean? What had they shown me that I didn’t immediately grab? If I had understood it completely, I would have just skimmed past that sentence.

So what did they actually mean by structuring a system so that the core code does not care about how you built the data it uses?

“It’s absurd,” I said. “That makes no goddamn sense,” I said.

But I still could not look past that absurd paragraph. How can a program not care about its own data? The data is what makes the process make sense in the first place! Why would I want to hide it? Imagine a game without characters. What were these guys yapping about?

Then it hit me: Wait. Abstractions.

The Gloves of the System

So far, our abstractions have just been compound primitive procedures. The program never really thinks about the primitives being used, yet it returns a complex answer that comes from a chain of primitives.

Data abstractions should be identical. Single data points should join other data points to make compound data structures. That sounds like it, but that is only half of the gist. What they truly meant is that the main program should never even know how the data is coupled.

It is like a doctor operating on a patient. His hands never directly know the feeling of raw flesh — but his gloves do. His hot knife does.

And then it clicked:

“No high-level function should directly manipulate raw data to return an output.”

How is that achieved? I don’t have the complete, final picture yet, but I can show you exactly what I have understood so far. Look at this standard approach:

typedef struct Person { 
    char *name;
    int age; 
} Person; 

void increase_age(Person *p) {
    p->age++; // Direct mutation!
}

That feels right. That feels quick. That feels smart. But in reality, that is — and forever will be, a fragile prototype. Why? Because the function directly reaches past the boundary to mutate the data context cells. Anyone can reverse that code and inject an unauthorized track like p->name = "hacked";.

Building the Intermediary Layer

Instead, this is how it must be built from an architectural standpoint:

typedef struct Person { 
    char *name;
    int age; 
} Person; 

// The Intermediaries (Our Gloves)
char* get_name(Person* p) { return p->name; }
int get_age(Person* p)    { return p->age; }
void set_name(Person* p, char* name) { p->name = name; }
void set_size(Person* p, int age)    { p->p_age = age; }

Now, when our business logic wants to execute an action, it goes through our system intermediaries:

void increase_age(Person *p) {
    int current_age = get_age(p); // Read through the glove
    current_age++;
    set_age(p, current_age);      // Write through the glove
}

Let’s look at the immense structural advantages this building pattern wins you:

  1. Encapsulation: The internal variables of Person are hidden. The rest of the program cannot reach in and mess with name or age directly.
  2. Maintainability: You can completely change the underlying struct definition down in the dark (e.g., add a middle_name field, or store age as a compact 1-byte integer) without breaking a single line of outside code that calls get_name or set_age.
  3. Validation: Inside your mutator glove (set_age), you can seamlessly enforce boundary checks: if (age < 0 || age > 150) { return; }. That is something you can never protect if random outside functions are modifying the integer cell directly.

This is the absolute bedrock of the highest-level systems architecture tools you use every day:

  • Database APIs: query, insert, update — intermediaries between your code and the raw storage engine blocks.
  • Network Protocols: send, recv — intermediaries between your data containers and the raw network wire.

Scaling to Complex Landscapes

You might be thinking, “Wait, how does this look when we move away from simple objects into complex data structures?” It is the exact same story.

Say you have a tree structure and you want to retrieve a name node inside it:

#include <string.h>

typedef struct Node {
    char* name;
    struct Node* left;
    struct Node* right;
} Node;

// The Selector Glove handles the traversal tracks completely isolated
char* get_name(Node* root, char* target) {
    if (root == NULL) return NULL;
    if (strcmp(root->name, target) == 0) return root->name;

    char* left_result = get_name(root->left, target);
    if (left_result != NULL) return left_result;

    return get_name(root->right, target);
}

void greet_person(char* name) {
    printf("Hello, %s!\n", name);
}

Now look at how clean and independent your execution track remains inside main():

int main() {
    // Assuming build_tree() handles our underlying structural allocations...
    Node* root = build_tree();

    // 1. The Getter Intermediary retrieves the data abstractly
    char* name = get_name(root, "John");

    // 2. The high-level function safely uses the data without knowing the tree mechanics
    if (name != NULL) {
        greet_person(name);
    }
    return 0;
}

You might already write your tracks this way, but now you understand the absolute Why.


메타데이터
post_id
f9d655862e19
slug
the-final-frontier-object-oriented-data-abstraction-theory-f9d655862e19
url
https://medium.com/@emodexohimai/the-final-frontier-object-oriented-data-abstraction-theory-f9d655862e19
canonical_url
https://medium.com/@emodexohimai/the-final-frontier-object-oriented-data-abstraction-theory-f9d655862e19
author_url
https://medium.com/@emodexohimai
status
ok
fetched_at
2026-08-30 03:18:16