2025-12-25 02:37:41 Displayed 123 times

Why my C is full of domain specific languages

I've been writing C for 4 years in a row now, and I spend a lot of time on :

  1. naming things
  2. respecting implicit contracts

AI's are of no help : the names are NIH and contracts are hard to understand unless you carefully read the code.

However these tasks are crucial for security and audit. If you cannot tell what e_rg.ac_ftl_47 means it means we're also lost. A lot of C programs contain very poorly named variable and struct member names. This comes from a time where every character you type would slow down the compiler at compiling so code golf was less a spare feature of a developer than an actual speed up in compilation time and memory consumption (remember, when all the RAM is taken the swap comes in at ATA speed). This was a long time ago and I think AI's will devise code with a lot of better names. No need for cargo-culting this kind of feature really unless you want the code to be write only.

I use hierarchical naming with same order or alphanum order, e.g. :

  typedef struct a s_a;
  typedef struct b s_b;
  s_a * a_b_c (s_a *a, s_b *b);

For contracts it becomes more complicated, for instance if you allocate memory using alloc you have to free it using free. When it's this simple AI's manage to work it through some point of reasoning, maybe I was lucky but it was not an isolated case, especially when you provide ASan output.

But when your contract is : for this operation I want TLS connection all the way. And in C there is no sub-classing, we refactor ! So every call to read, write, recv and send have to be rewritten TLS_read, TLS_write, etc. That is a simple refactor unless your code has other modules with read and write functions defined. In this case the AI will iterate on each file and inspect headers one by one. The locality of C function names makes it hard to just search and replace. In C there is no way to mean : take this socket and make it TLS. You enter another level of abstraction : the one of the application's layer data in OSI model and TLS encryption which is useful for securing client/server connections from data theft or tampering.

So why domain specific languages ? Well I would argue that in response to all these implicit contracts we enforce in the code we had to devise a language extension or restriction that we can apply generally and go through enforcing the contracts through the use of domain specific embedding of code contracts. In C that's the most you can expect from the libc.

But KC3 would prove otherwise : you can build abstractions like s_buf (our custom buffer object) that will accept just a few function pointers and give you an infinitely and arbitrarily sub-classable buffer object. And in this buffer object you can either read or write. The buffer is made for reading or writing but not both. If you want read/write operations you need two buffers as the refill and flush functions have different meanings on the whole buffer object. This buffer with a single function pointer could read/write to TLS through all its current operators (pretty printer and marshalling included). So with libkc3 you can plug-in buffer operations in a function callback for refill (read) or flush (write) with a user pointer attached. That's actually a closure.

Merry xmas !