Interlude 2 - Lessons learned

Advent of Code 2015

Adrien Foucart

2026-03-15

[Back to index]

Eight puzzles and sixteen stars in, what have I learned so far? There are two main lessons that I think I want to ramble about for a bit: reading the docs, and object-oriented C.

Read. The. Docs

RTFM, as we say. Do we still say that? I haven’t heard that in a while. Anyway. I’m a big fan of the Python Standard Library. I think it’s very well designed, it has a lot of super useful modules (itertools and functools come to mind) and, most importantly for my point here, it has a very intuitive and cohesive interface. When I see the name of a function and of its parameter, I usually get a very good idea very quickly of what it’s doing.

That is very much not the case with the C Standard Library. Every time I use a new function, I think I know what it does, and I use it, and everything crashes or gives me a weird output. Then I read more carefully and go: oooh, that’s what it’s doing!

strcmp is a good example. I search for a way to compare two null-terminated strings, and find this function. I read the signature:

int strcmp( const char* lhs, const char* rhs );

And the first line of the docs:

Compares two null-terminated byte strings lexicographically.

And I go: “great! exactly what I need!”. Then I code something like:

if (strcmp(some_string, some_other_string)){
    // code that needs to run if the strings are the same
}

Because in my mind, strcmp does something like String.equals in Java, providing a way to test equality for an object where == won’t work.

But the very next line that I skipped says:

The sign of the result is the sign of the difference between the values of the first pair of characters (both interpreted as unsigned char) that differ in the strings being compared.

This is very clear. The Return value section also says:

Negative value if lhs appears before rhs in lexicographical order.

Zero if lhs and rhs compare equal.

Positive value if lhs appears after rhs in lexicographical order. 

And they even provide an also-very-clear example:

void demo(const char* lhs, const char* rhs)
{
    const int rc = strcmp(lhs, rhs);
    const char* rel = rc < 0 ? "precedes" : rc > 0 ? "follows" : "equals";
    printf("[%s] %s [%s]\n", lhs, rel, rhs);
}

I’m not complaining against the docs here. This is perfectly unambiguously stated. It’s all on me. But I get into this kind of mistakes so often that I feel like I don’t get C yet, not in the same way that (I think) I get Python.

OOC?

Object-oriented C is fun! I didn’t even really know you could do that, to be honest. I only did a little bit of C when I was a student, then some C++ for my master thesis, then I moved on to mostly Python. I always think of C++ as “the object-oriented C” which is probably a common mistake. It comes from looking at “object-oriented programming” as a set of features in the language rather than a design philosophy.

Sure, if I write:

typedef struct {
    x: int,
    y: int
} vector;

vector* vector_construct(int x, int y){
    vector* c = malloc(sizeof(vector));
    c->x = x;
    c->y = y;
    return c;
}

void vector_destruct(vector* c){
    free(c);
}

void vector_add(vector* v, vector* delta){
    v->x += delta->x;
    v->y += delta->y;
}

I don’t get the nice benefit of being able to do something like:

vector* v = new vector(5, 3);
v->add(new vector(-1, 2));

But I feel the spirit of this is the same:

vector* v = vector_construct(5, 3);
vector* delta = vector_construct(-1, 2);
vector_add(v, delta);
vector_destruct(delta);
// ...
vector_destruct(v);

I enjoy having the opportunity to think about the code in object-oriented terms, while having to also keep in mind all the memory-handling shenanigans. I mean, I’m not sure I’d enjoy it if there were any stakes, but for this fun little advent of code journey, I do think it’s fun!