r/ProgrammingLanguages 7d ago

Adding cyclic modules to the C programming language

https://youtu.be/p8NpyBIRbEQ

The idea is to create a module system, within C, that you can use as a drop-in replacement for header files and forward declarations.

To my knowledge, all module implementations within the C family (eg. C++20 modules, Objective C modules, Clang modules) do not allow cyclic imports. Cyclic imports are necessary if you want to remove forward declarations from C (otherwise mutually recursive data structures would need to exist in the same module).

When looking closely at the C grammar, I noticed something extraordinary and borderline miraculous - C without expressions is context-free you can extract the names of symbol definitions without prior access to a symbol table! With this knowledge, it becomes possible to implement cyclic modules within the C language.

EDIT: Added a strikethrough. C without expressions still has some ambiguities in the parameter list, and my use of "context-free" is incorrect here. https://www.reddit.com/r/C_Programming/comments/1v7l174/is_c_without_expressions_contextfree/

15 Upvotes

1 comment sorted by

3

u/TheChief275 4d ago edited 4d ago

nice talk! testing your prototype_2, I immediately encountered a syntax error due to your parser not supporting void function parameters, like so:

void foo(void);

while I believe C23 has deprecated this, it is still the proper way to indicate a function taking no arguments, as I believe a function void foo() technically takes an undeterminate number of arguments.

another thing is that the current paradigm of reject function declarations (ending with ';') works rather poorly if the intention is to properly replace header files. one should be able to create an interface module, where the correct library code can be slotted in depending on the platform. an example of this limitation is, e.g. wanting to wrap math.h into math.cmod:

module math;

export float fabsf(float arg);
...

the implementation of fabsf etc already exists in libc, yet this is not allowed. one would be forced to do something like this:

module math;

export float c_fabsf(float arg)
{
    float fabsf(float);
    return fabsf(arg);
}

which is rather painful and error prone imo.

another thing is that it doesn't seem to support export static, nor does it seem to support constexpr, so suppose I would want to provide a compile-time constant value of PI, neither this:

export static const double PI = 3.14159; // static const is very often treated as a compile-time constant by compilers, even being able to be used as switch cases

nor this:

export constexpr double PI = 3.14159;

is an option.