3 ms·
I hope this isn't too much of a derail. I'm not proficient in C, and am translating a C module to Rust. My biggest complaint is there's so much DRY! Functions,
by the__alchemist 5y ago
I hope this isn't too much of a derail. I'm not proficient in C, and am translating a C module to Rust. My biggest complaint is there's so much DRY! Functions, variables etc are all prefixed with the module names, presumably due to lack of namespaces. The `.c` vs `.h` dichotomy is also DRY. The subset language that uses `#` is also a bit of a mess.
- Jtsummers 5y agoYou're using DRY oddly, but I presume you mean "there is so much duplication" (which is the opposite of DRY)? For the .c/.h part, it's because of use (or intended use). Header files are meant to be specifications (though a lot of implementation ends up in them, annoyingly). It actually is an example of DRY thanks to C's need to forward declare things. You can't call a function the compiler doesn't know about, for instance, so you declare (not define) it in the header if it's defined in an external module. If you didn't have the headers, you'd need to copy/paste or handwrite the declarations everywhere.
- the__alchemist 5y agoYou're right - I was referring to DRY violations. Why do you think there needs to be a declaration beyond the definition? The definition is enough information for the compiler, and having both is a DRY violation.
- Jtsummers 5y agoYou need the declarations because the compiler requires it, it's not something that I just thought up. If you don't, then you get two different declarations for bar in the following. The one you intended (char bar(int)) and the one you didn't (int bar()): int foo(int n) { char c = bar(n); ... } char bar(int n) { ... } The definition is not enough information for the compiler in a case like this, which is also essentially the case for any externally defined function. The compiler doesn't know anything about those unless its declaration is provided, which is what's in the header files.
- the__alchemist 5y agoThere's one definition of `bar` there: It's a function that accepts an `int` as a parameter, and outputs a `char`.
- Jtsummers 5y agoDid I say there were two definitions? I said there are two declarations. Try using a function with a return type other than int before it has been defined or declared in C and see what happens when you compile it.
- the__alchemist 5y agoThe function is declared/defined/described/written once, and used once. There is no ambiguity. I don't understand your point about using a function that hasn't been declared. Of course it won't work! I understand your point about using header files as interfaces to third-party code, but there are ways of doing that that don't involve duplicating all functions, structs etc.
- Jtsummers 5y agoThe function is used once, and because it occurs before the actual definition (and there was no forward declaration) an implicit declaration occurs (the erroneous int bar()). When the function definition is later reached by the compiler, its signature doesn't match the implicit declaration's signature, causing the problem. If the function signature matches the implicit declaration, then there is no problem: int main(int argc, char* argv[]) { printf("%d\n", foo(10)); return 0; } int foo(int n) { return n - 1; } Will work just fine, giving you only a warning but will print out "9" as expected.
- the__alchemist 5y agoYikes! The implicit declaration, if used before (as in a lower line number than the function definition?) sounds like a trap, and at the root of this.
- Gibbon1 5y agoHeader files are a historical legacy from when C was developed. Because machines were small compilers/languages were designed to do single pass compilation on modules which were then linked. Friends of mine who are actual CS majors say with C it's not fixable without changes to the language. With Java or C# the compiler can do a pass and extract the object definitions. But because of ambiguous syntax and majorly because of the preprocessor it's not possible with C as it stands.
- P_I_Staker 5y agoYou can call a function the compiler doesn't know about, but god help you if there happens to be an identical symbol in the table; it will link to literally anything, including an integer. This should pretty much always be turned off by setting implicit functions to be errors. Also, this explains all the prefixing that OP was complaining about lol, or at least that's one reason. I saw a particularly bad bug, due to poor naming decisions. Less is not always more, even if it annoys you.