https://www.lelanthran.com/chap9/content.html
The C Programming Language: Myths and Reality (1)
The Internet is the first thing that humanity has built that
humanity doesn't understand, the largest experiment in anarchy
that we have ever had.
-- Eric Schmidt
---------------------------------------------------------------------
previous:
Centerpoint of an Image: Harder than it Looks
Contents
Posted by Lelanthran
2023-06-28
Context
Balance!
Balance!
All too often someone, somewhere, on some forum ... will lament the
lack of encapsulation and isolation in the C programming language.
This happens with such regularity that I now feel compelled to
address the myth once and forever. This means I can post links to
this page for any future assertion of that nature without having to
retype the explanation in everytime someone is wrong on the internet
Just to be clear, C is an old language lacking many, many, many
modern features. One of the features it does not lack is
encapsulation and isolation.
Myth: C has no equivalent to "private"
Lets look at a class definition that has private members; after all,
that's where the isolation comes from, right? If all the fields were
public, then it'd be just like C but with inheritance.^1
class StringBuilder {
private String payload;
public void Append(String snippet) {
payload = payload + snippet;
}
};
Any attempt by a caller to access the field payload results in a
compilation error. Pretty nifty. You can see why this can be useful.
PrivateWrong!
Private Wrong, a Major Pain!
The C programming language doesn't have classes^2, but it does have
structs, which look like this:
struct StringBuilder {
char *payload;
};
void Append(struct StringBuilder *obj, const char *snippet);
There are no access modifiers; all fields in a struct are public.
This is why there is always someone complaining that C doesn't
provide encapsulation or isolation: everything is visible in a
struct, to everyone, all the time, even the callers of the function
Append().
Reality bytes
The complaint isn't necessarily true. While you can indeed dump
everything into a single source file and call it a day, the more
common option is to split things into different files and modules.
When code is in different source files, they are are encapsulated
into a module. Each "module" in C consists of an interface file which
callers can use to call functions which exist in the implementation
file.
The interface file, called the header file (with a file extension of
.h) is a contract that tells the user of the module what functions
and types are needed to use the implementation, frequently simply
called the source file. After compilation, you might have a compiled
implementation, and thus may not even have access to the source code
of Append().
And ... Ta Da!
The calling programs have to use the header file in order to make
legal (under C) calls to Append(); the implementation might only be
available in compiled form, after all, and not source code form.
So, in the header you do:
typedef struct StringBuilder StringBuilder;
void Append(StringBuilder *obj, const char *snippet);
In the implementation you do:
struct StringBuilder {
char *payload;
};
void Append(StringBuilder *obj, const char *snippet)
{
...
}
And ... that's it!
Now any code using a struct of type StringBuilder can use it all they
want to build up a string, but they can never see the fields within
it.
Hell, they cannot even malloc() their own StringBuilder instance,
because even the size of the StringBuilder is hidden. They have to
use creation and deletion functions provided in the implementation as
specified in the interface.
But, there's more ...
So now you have a way to create an instance of an object with all its
fields hidden from any caller. You have also forced all callers to
stop messing about with the fields in your object - all access to the
object is guarded by the functions in the implementation (as
specified in the header).
You don't have inheritance, but you do have one very important
characteristic: you can create objects from this class, and use them,
from within Python.
Or PHP.
Ruby, even.
It'll work with most Lisp implementations.
You can call it from Java.
In fact, I don't believe there is a single programming language in
common use which cannot use this object. In many cases the programmer
from the other language won't even have to do much work to use this
class.^3]
My Makefiles already have rules to automatically generate the
interface so that the C code I write in this manner is callable from
within Android applications.
You got it, I'll stop now
And that's how you get encapsulation and isolation with strong
guarantees in C. Don't believe everything you read on the internet.^4
---------------------------------------------------------------------
previous:
Centerpoint of an Image: Harder than it Looks
Contents
Posted by Lelanthran
2023-06-28
---------------------------------------------------------------------
1. I'm being sarcastic, so relax.-[?]
2. Some would argue it doesn't have any class either.-[?]
3. See swig.-[?]
4. Except for this blog, of course. I'm obviously a paragon of
honesty and wisdom, except for when I'm not.-[?]