Parameterized types in C using the new tag compatibility rule

(nullprogram.com)

53 points | by ingve 6 hours ago ago

15 comments

  • fuhsnn 2 hours ago ago

    The recent #def #enddef proposal[1] would eliminate the need for backslashes to define readable macros, making this pattern much more pleasant, finger crossed for its inclusion in C2Y!

    [1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3531.txt

    • cb321 2 hours ago ago

      While long-def's might be nice, you can even back in ANSI C 89 get rid of the backslash pattern (or need to cc -E and run through GNU indent/whatever) by "flipping the script" and defining whole files "parameterized" by their macro environment like https://github.com/c-blake/bst or https://github.com/glouw/ctl/

      Add a namespacing macro and you have a whole generics system, unlike that in TFA.

      So, it might add more value to have the C std add an `#include "file.c" name1=val1 name2=val2` preprocessor syntax where name1, name2 would be on a "stack" and be popped after processing the file. This would let you do types/functions/whatever "generic modules" with manual instantiation which kind of fits with C (manual management of memory, bounds checking, etc.) but preprocessor-assisted "macro scoping" for nested generics. Perhaps an idea to play with in your slimcc fork?

  • unwind 4 hours ago ago

    I think this is an interesting change, even though I (as someone who has loved C for 30+ years and use it daily in a professional capacity) don't immediately see a lot of use-cases I'm sure they can be found as the author demonstrates. Cool, and a good post!

  • rwmj 3 hours ago ago

    Slighty off-topic, why is he using ptrdiff_t (instead of size_t) for the cap & len types?

    • r1chardnl 2 hours ago ago

      From one of his other blogposts. "Guidelines for computing sizes and subscripts"

        Never mix unsigned and signed operands. Prefer signed. If you need to convert an operand, see (2).
      
      https://nullprogram.com/blog/2024/05/24/

      https://www.youtube.com/watch?v=wvtFGa6XJDU

      • poly2it an hour ago ago

        I still don't understand how these arguments make sense for new code. Naturally, sizes should be unsigned because they represent values which cannot be unsigned. If you do pointer/size arithmetic, the only solution to avoid overflows is to overflow-check and range-check before computation.

        You cannot even check the signedness of a signed size to detect an overflow, because signed overflow is undefined!

        The remaining argument from what I can tell is that comparisons between signed and unsigned sizes are bug-prone. There is however, a dedicated warning to resolve this instantly.

        It makes sense that you should be able to assign a pointer to a size. If the size is signed, this cannot be done due to its smaller capacity.

        Given this, I can't understand the justification. I'm currently using unsigned sizes. If you have anything contradicting, please comment :^)

        • ncruces 25 minutes ago ago

          > It makes sense that you should be able to assign a pointer to a size. If the size is signed, this cannot be done due to its smaller capacity.

          Why?

          By the definition of ptrdiff_t, ISTM the size of any object allocated by malloc cannot be out of bounds of ptrdiff_t, so I'm not sure how can you have a useful size_t that uses the sign bit?

        • sim7c00 39 minutes ago ago

          I dont know either.

          int somearray[10];

          new_ptr = somearray + signed_value;

          or

          element = somearray[signedvalue];

          this seems almost criminal to how my brain does logic/C code.

          The only thing i could think of is this:

          somearray+=11; somearray[-1] // index set to somearray[10] ??

          if i'd see my CPU execute that i'd want it to please stop. I'd want my compiler to shout at me like a little child, and be mean until i do better.

          -Wall -Wextra -Wextra -Wpedantic <-- that should flag i think any of these weird practices.

          As you stated tho, i'd be keen to learn why i am wrong!

        • foldr 18 minutes ago ago

          Stroustrup believes that signed should be preferred to unsigned even for values that can’t be less than zero: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p14...

  • tialaramex 2 hours ago ago

    It seems as though this makes it impossible to do the new-type paradigm in C23 ? If Goose and Beaver differ only in their name, C now thinks they're the same type so too bad we can tell a Beaver to fly even though we deliberately required a Goose ?

    • yorwba 2 hours ago ago

      "Tag compatibility" means that the name has to be the same. The issue the proposal is trying to address is that "struct Goose { float weight; }" and "struct Goose { float weight; }" are different types if declared in different locations of the same translation unit, but the same if declared in different translation units. With tag compatibility, they would always be treated as being the same.

      "struct Goose { float weight; }" and "struct Beaver { float weight; }" would remain incompatible, as would "struct { float weight; }" and "struct { float weight; }" (since they're declared without tags.)

      • tialaramex 2 hours ago ago

        Ah, thanks, that makes sense.

  • Surac 3 hours ago ago

    i fear this will make slopy code compile more often OK.

    • poly2it an hour ago ago

      Dear God I hope nobody is committing unreviewed LLM output in C codebases.

    • ioasuncvinvaer 2 hours ago ago

      Can you give an example?