How to write generics in C
Mood
thoughtful
Sentiment
positive
Category
tech
Key topics
C programming
generics
type safety
The article discusses how to implement generics in C, a feature typically associated with higher-level languages, and provides a practical example.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
50m
Peak period
39
Day 1
Avg / period
39
Based on 39 loaded comments
Key moments
- 01Story posted
11/15/2025, 1:58:09 PM
3d ago
Step 01 - 02First comment
11/15/2025, 2:48:11 PM
50m after posting
Step 02 - 03Peak activity
39 comments in Day 1
Hottest window of the conversation
Step 03 - 04Latest activity
11/15/2025, 5:01:27 PM
3d ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
When the other option is "ask the developers to practice discipline", an option that doesn't require that looks awfully attractive.
That being said, I'm not a fan of the described method either. Maybe the article could have shown a few more uses of this from the caller perspective.
The solution to this doesn't have to be "rewrite everything in Rust", but it does mean that you need to provide safe, easy implementations for commonly-screwed-up patterns. Then you're not asking people to be perfect C programmers; you're just asking them to use tools that are easier than doing the wrong thing.
Sure, but since there's 10x more opaque footguns in C+++, there is much less discipline needed than when coding in C++.
The footguns in C are basically signed-integer over/underflows and memory errors. The footguns in C++ include all the footguns in C, and then add a ton more around object construction type, object destruction types, unexpected sharing of values due to silent and unexpected assignments, etc.
Just the bit on file-scope/global-scope initialisation alone can bite even experienced developers who are adding a new nonlocally-scoped instance of a new class.
This is a rather crude misrepresentation; most C programmers who need a higher level of abstraction than C reach for Java, C# or Go over C++.
IOW, acknowledging that C++ has improvements over C still does not make the extra C++ footguns worth switching over.
When you gloss over the additional footguns, it looks like you're taking it personally when C programmers don't want to deal with those additional footguns.
After all, we don't choose languages based on which one offers the most freedom to blow your leg off, we tend to choose languages based on which ones have the most restrictions against blowing your leg off.
If your only criteria is "Where can I get the most features", then sure, C++ looks good. If your criteria is "Where are the fewest footguns", then C++ is at the bottom of the list.
My criteria is being as safe as Modula-2 and Object Pascal, as bare minimum.
C++ offers the tools, whereas WG14 has made it clear they don't even bother, including turning down Dennis Ritchie proposal for fat pointers.
> it is called life experience meeting those kind of persons
Looks like you are confirming that you are taking it personally.
I don't understand why, though.
You cannot imagine a programmer that wants fewer footguns?
Well, that's a novel take: "Opting for fewer footguns is careless". :-)
It's probably not news to you that your view is, to put it kindly, very rare.
And to finish this, as I won't reply any further,
"A consequence of this principle is that every occurrence of every subscript of every subscripted variable was on every occasion checked at run time against both the upper and the lower declared bounds of the array. Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to--they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980 language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law."
-- C.A.R Hoare's "The 1980 ACM Turing Award Lecture"
TS, on the other hand, is usable wherever JS is, and its disadvantages are much less pronounced.
C++ has many advantages over C, but it also brings some clear disadvantages that matter more when you want to be aware of every operation. When comparing language A against language B, it's not enough to consider what A does better than B; you also have to consider what it does worse.
That's why I don't think that the comparison to TS/JS is apt. Some may argue that C++ has even more advantages over C than TS has over JS, but I think it's fairly obvious that its disadvantages compared C are also bigger. For all its advantages, there are some important things that C++ does worse than C. But aside from adding a build step (which is often needed, anyway), it's hard to think of important things that TS does worse than JS.
The problems I am guessing start when you are tempted into using the rest of the features one by one. You have generics. Well next let's get inheritance in. Now a bit of operator overloading. Then dealing with all kinds of smart pointers...
You could start with a Perl script that looks at the output of “clang++ -Xclang -ast-dump” and verifies that only permitted AST nodes are present in files that are part of the project sources.
I think a better way is possible using `_Generic`[1]. Even though it would still use macros, the resulting code is much more readable.
---------------------------
[1] `_Generic` comes with its own problems too, of course.
The readability of error messages was always my beef with macro-based generics. Maybe 15 years ago I played around with using UTF characters for the brackets and type separators when translating a generic type into name-mangled type, so at least the generated source and error messages would still be clear and understandable.
Robust UTF support for identifiers and preprocessor was still kind of inconsistent across compilers though, so it only sort of worked. I expect this has improved considerably now though, so maybe I should try again and write something up. You can embed a surprising amount of advanced programming language theory into suitable name resolution.
This is how you do it:
I use this technique in my hobby projects as it has worked out the best for me of the options I’ve explored.
This is secretly two way generation: you can edit The generated file, recompiling until until the code works, commit that, and then edit the M4 inputs until CI passes.
As another example of the same principle, whenever I am required to have a requirements.txt and setup.cfg in the same puthon library, I now verify that they match in a CI check instead of trying to single source of truth by having a setup.cfg import the requirements.txt through some clever hack.
“How to write type safe generics using the C preprocessor”
24 more comments available on Hacker News
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.