Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is compile-time encapsulation in C?

Tags:

c

When I was researching the advantages of C over C++, I came across this paragraph:

Standard way in C to do encapsulation is to forward declare a struct and only allow access to its data through functions. This method also creates compile time encapsulation. Compile time encapsulation allows us to change the data structures members without recompilation of client code (other code using our interface). The standard way of doing encapsulation C++ on the other hand (using classes) requires recompilation of client code when adding or removing private member variables.

I understand how forward declaring a struct and accessing its members through functions hides the struct's implementation details. What I don't understand is this line specifically:

Compile time encapsulation allows us to change the data structures members without recompilation of client code (other code using our interface).

In what scenario is this applicable?

like image 337
mbl Avatar asked Nov 17 '19 13:11

mbl


2 Answers

A possible real-world scenario where this would occur is when a database library, written in the days when hard-disk space was very limited, used a single byte to store the 'year' field of a date (e.g. 11-NOV-1973 would have 73 for the year). But, when the Year 2000 came along, this would no longer be sufficient, and the year had then to be stored as a short (16-bit) integer. The relevant (much simplified) header for this library could be this:

// dbEntry.h
typedef struct _dbEntry dbEntry;

dbEntry* CreateDBE(int day, int month, int year, int otherData);
void DeleteDBE(dbEntry* entry);
int GetYear(dbEntry* entry);

And a 'client' program would be:

#include <stdio.h>
#include "dbEntry.h"

int main()
{
    int dataBlob = 42;
    dbEntry* test = CreateDBE(17, 11, 2019, dataBlob);
    //...
    int year = GetYear(test);
    printf("Year = %d\n", year);
    //...
    DeleteDBE(test);
    return 0;
}

The 'original' implementation:

#include <stdlib.h>
#include "dbEntry.h"

struct _dbEntry {
    unsigned char d;
    unsigned char m;
    unsigned char y;    // Fails at Y2K!
    int dummyData;
};

dbEntry* CreateDBE(int day, int month, int year, int otherData)
{
    dbEntry* local = malloc(sizeof(dbEntry));
    local->d = (unsigned char)(day);
    local->m = (unsigned char)(month);
    local->y = (unsigned char)(year % 100);
    local->dummyData = otherData;
    return local;
}

void DeleteDBE(dbEntry* entry)
{
    free(entry);
}

int GetYear(dbEntry* entry)
{
    return (int)(entry->y);
}

Then, at the approach of Y2K, this implementation file would be changed as follows (everything else being left untouched):

struct _dbEntry {
    unsigned char d;
    unsigned char m;
    unsigned short y;   // Can now differentiate 1969 from 2069
    int dummyData;
};

dbEntry* CreateDBE(int day, int month, int year, int otherData)
{
    dbEntry* local = malloc(sizeof(dbEntry));
    local->d = (unsigned char)(day);
    local->m = (unsigned char)(month);
    local->y = (unsigned short)(year);
    local->dummyData = otherData;
    return local;
}

When the client needs to be updated to use the new (Y2K-safe) version, no code changes would be required. In fact, you may not even have to re-compile: simply re-linking to the updated object library (if that's what it is) could be sufficient.

like image 73
Adrian Mole Avatar answered Oct 23 '22 06:10

Adrian Mole


Note: The following list will be non-exhaustive. Edits are welcome!

The applicable scenarios include:

  • Multi-module applications where you don't want recompilation for some reason.
  • Structures used in libraries where you don't want to force the users of the library to recompile each time you change a (published) structure.
  • Structures that contain different elements on the different platforms the module works on.

The most known structure of this kind is FILE. You just call fopen() and get a pointer if successful. This pointer is then handed over to each other function that works on files. But you don't know - and you don't want to know - the details, like contained elements and the size.

like image 31
the busybee Avatar answered Oct 23 '22 07:10

the busybee