Hacker News new | ask | show | jobs
by thxg 1409 days ago
One slight variation on the getaddrinfo()/freeaddrinfo() approach is what (among many others) GMP [1] and its derivatives do: For every struct or custom type, you systematically get

    void type_init(type *t, [...]);
    void type_clear(type *t, [...]);
This is essentially explicit constructors and destructors in C, and one can legitimately argue that it is clunky, verbose and error-prone.

However, if we are constrained to a C API, it does have one important practical quality in my experience: Because it is always the same, it eases the mental load on both the API's user and the API's implementer, especially if there are many such types involved.

[1] See e.g. https://gmplib.org/manual/Initializing-Integers

4 comments

> and one can legitimately argue that it is clunky, verbose and error-prone.

Clunky and verbose, yes, error-prone no. The APIs that do that are generally much more clear about ownership, and thus much easier, IMO, to write correct code for. Much worse is the API that returns you a pointer with no obvious mechanism to free it. Is it tied to the lifetime of an input to the function that returned it? Is it a global and this API is completely thread-unsafe? Am I leaking memory?

> explicit constructors and destructors in C

Exactly, and that’s the right way to do it. In a language without implicit destructors/finalizers, you need a way for callers to say “okay, I’m done with this thing.” And even with GC, you need finalizers to take care of non-memory resources. This may be clunky in C, but that’s what you get in a language that makes you be explicit.

CoreFoundation at Apple had a similar convention. Any memory obtained by an API named Create or Copy would have similar Delete method that always had to be called.
Especially for certain generics (e.g. hashmaps) you might want to have different allocators without creating a whole separate type: for example a global one, a threadlocal arena, etc.