C3 is switching to signed sizes by default after five years, concluding unsigned sizes cause more bugs than they prevent in systems languages.
Key Takeaways
Unsigned sizes force pervasive signed/unsigned casts or implicit promotion rules, both of which silently hide arithmetic bugs.
C3’s rule promoting int + uint to int broke down at division and modulo, producing plausible but wrong results near INT_MAX.
Ring buffer offset math with unsigned types produces wrong wrap behavior that the compiler cannot detect; signed types make the error obvious via negative values.
Go and Java both chose signed sizes deliberately; Go’s designers knew the unsigned cost and rejected it anyway.
C3 0.8.0 renames the signed size type to sz and drops implicit signed/unsigned conversion entirely, making unsigned use visibly exceptional.
Hacker News Comment Review
Commenters are split: systems programmers with embedded or low-level backgrounds push back, arguing full word range and modular arithmetic are genuinely needed and signed sizes just shift boundary problems rather than eliminate them.
The Rust experience is disputed: several commenters say usize causes minimal friction if you keep value origins consistent with destination types, contradicting the article’s cast-proliferation argument.
A recurring caveat is that signed overflow is UB in C/C++, so the “negative value signals wrongness” argument only cleanly holds in languages like C3 with defined two’s complement behavior.
Notable Comments
@cperciva: calls the design rationale weak, noting compiler warnings already flag tautologous and mixed-sign comparisons without language-level changes.
@lerno: key asymmetry is that unsigned overflow yields a plausible wrong value while signed overflow yields an obviously wrong negative one.