Map::operator[] Should Be Nodiscard
Key topics
The debate rages on about whether C++'s `map::operator[]` should be marked as `nodiscard`, sparking a broader discussion on the language's evolution and its competition from newer systems languages. Some commenters, like GuB-42, argue that C++'s "kitchen sink" approach is both a strength and a weakness, while others, like pjmlp, point out that would-be C++ replacements still rely heavily on C++ infrastructure. As the conversation unfolds, it becomes clear that bootstrapping – i.e., rewriting the OS and compiler in the replacement language – is a major hurdle for these emerging languages. The discussion reveals a consensus that truly replacing C++ will require significant advancements in areas like compiler design and low-level programming.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
5d
Peak period
33
120-132h
Avg / period
14.6
Based on 73 loaded comments
Key moments
- 01Story posted
Dec 19, 2025 at 10:45 AM EST
15 days ago
Step 01 - 02First comment
Dec 24, 2025 at 7:47 AM EST
5d after posting
Step 02 - 03Peak activity
33 comments in 120-132h
Hottest window of the conversation
Step 03 - 04Latest activity
Dec 26, 2025 at 7:01 AM EST
8 days ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
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.
> This is why other systems languages are taking off
Great! It is not a competition. If you think that Rust is a better choice, use Rust, don't make C++ into Rust. Or maybe try Carbon, it looks like it is the language you want. But if you have some old dogs you want to keep alive, then use C++, that's what it is for.
For the time being that are still being written with C++ infrastructure though.
It would be great if those wannabe C++ replacements were fully bootstraped.
Your posts about the Wirth tradition languages and their implementations are typically well founded and I haven’t read much on this aspect. If you just have a reference you’d suggest that would be more than enough (if you don’t want to take time explaining what has been written elsewhere).
Meanwhile the Oberon community diverged into Active Oberon, Zonnon, Component Pascal.
However for Niklaus Wirth those were distractions, and he looked into how to take further features away from Oberon, which was already less feature rich than Modula-2.
There were a few revisions from Oberon-07 between 2008 and 2016, each removing even more language features, before his retirement from computing world.
"Differences between Revised Oberon and Oberon"
https://people.inf.ethz.ch/wirth/Oberon/Oberon07.pdf
"Porting the Oberon Compiler from Oberon to Oberon-07"
The latest revision being,
https://people.inf.ethz.ch/wirth/Oberon/Oberon07.Report.pdf
Niklaus Wirth goal became how to remove "needless fluff" out of Oberon, and still get enough features to have a systems programming language with a GC.
Historically, pjmlp has pushed very strongly for languages attempting to take the place of C and C++ at the infrastructure layer can not claim to have supplanted those two until their own compiler and related infrastructure is not dependent on C++ (LLVM in particular). I tend to sympathize with this view, it is really hard to take a language’s claim to have supplanted C++ and be the only fit for use language going forward, but then is dependent on millions of lines of the languages they disparage.
As a counter however, it’s rather difficult to expect a language to overcome thousands of person-years of work on a compiler like LLVM and tens of thousands of person-years on Linux. The newer languages should be able to make an articulate case that throwing away so much work is not a viable approach and just use what exists now but keep the new languages on all greenfield projects.
However, despite overblown complaints about the RESF, the community both in commentary and in practice has been extremely vocal that any language that does not have Rust’s memory safety model is not suitable for any new project or further use in existing projects. And while the RIIR meme is for the most part a message board strawman, again, the community surrounding Rust is busy reimplementing coreutils in Linux, putting Rust in the kernel, and rewriting the userland executables that most Linux workflows are based around (ripgrep being the most successful in this group).
It is clear that Rust, the community of users (if not the language as an independent entity) clearly wants to supplant both C and C++ at all levels of the computing stack. The push for Rust in the Linux kernel is enough evidence to support the concept at the most pervasive level.
Continuous references to wide spread adoption and endorsements by ‘big tech’ is used to frame Rust as the only viable option going forward. Blog posts, Reddit threads, and board comments all routinely take the stance that memory-safety (as defined by Rust) is ‘table stakes’ for any development occuring in current year.
It feels disingenuous to pretend that Rust is not trying to become the industry standard language in the way C and C++ is today and has been for multiple decades. And given that aim, I think talking about Rust, as the name for both the language and its community of users and supporters, is working to supplant C and C++.
Given all that, I find it fair to discuss the fact that while busy trying to maneuver itself into every space in the tech industry (from embedded all the way up to the front end for web web apps) and find some success in doing so Rust is still reliant on C++ infrastructure particularly for compilation. I was responding to a pair of comments about the desire to see languages that want to be the bedrock of the computing stack bootstrapped. I think Rust absolutely wants to be such a bedrock language and as such, I don’t think wanting it to be bootstrapped and not reliant on the C++ it want to replace is an unreasonable standard to hold the language to.
[0] https://github.com/rust-lang/rustc_codegen_cranelift
My comment was focused on the fact that Rust is not using a Rust compiler and therefore is relying on deep and complex C++ infrastructure while working to supplant the same at the lowest levels of the computing stack.
I was also commenting, up the thread, in a chain of comments about a perceived shortcoming of Rust’s implementation (i.e. it’s not being bootstrapped) and why some people view that as a negative.
We absolutely know that if Rust didn't offer LLVM you'd see C++ people saying "Rust doesn't even have a proper optimiser". So now what you're asking for isn't just "a Rust backend" which exists as others have discussed, but a Rust alternative to LLVM, multiple targets, lots of high quality optimisations, etc. presumably as a drop-in or close approximation since today people have LLVM and are in production with the resulting code.
Pointing out a language still needs C++ at compile time is a reasonable critique of "supplanting C++", but it's not a reasonable critique of "wanting to be a foundational language of the computing stack". Rust is the latter. (And even then it's too early to worry about compilers.) (And Rust is making good progress on compilers anyway.)
Engineering is all about tradeoffs. Responding to perceived zealotry with more, but different, zealotry makes it harder to have actual discussions.
LLVM is best in class at what it does. Until someone else decides to make something like LLVM in Rust, it's not realistic to use something else. That's just engineering. The choices here directly refute these sorts of zealotry claims, that is, it's not incoherence in what's being done, it's that you are attributing something to a large group of people who have a wide variety of beliefs.
This would require (re)writing the OS in the replacement language
Also need assembler to be taken seriously, which Rust can’t do last I checked
I think Zig might possibly beat Rust's timeline here for a "No C/C++" toolchain. That is if its lead doesn't burn himself out.
I have never seen better documentation for programming languages than cppreference. Can you list such docs?
One thing about Google living so close to head with its libc++ is that it encounters the issues downstream users will encounter, just long before everyone else. It saw this development within a day or two of the or getting merged.
The idiom is unfortunately common in C++ codebases around the world so this was a good predictor that many other users will be broken. It isn’t necessarily erroneous, unlike many of the other no-discard additions made in this patch series.
So the question becomes, “Are the false positives worth the true positives?” Not just for Google, but for the entire user base.
It is reasonable to disagree on this, and often library writers up to date on the latest and greatest miss the issues this sort of change will cause.
Anyway, this article illustrates a great reason why C++ is a beautiful mess. You can do almost anything with it, and that comes at a cost. It's the polar opposite ethos of "there should be one clear way to do something" and this sort of thing reminds me why I have replaced all of my systems language needs with Rust at this point, despite having a very long love/hate relationship with both C and C++.
> We propose that when_ is used as the identifier for the declaration of a variable, non static class member variable, lambda capture or structured binding. the introduced name is implicitly given the [[maybe_unused]] attribute.
> In contexts where the grammar expects a pattern matching pattern,_ represents the wildcard pattern.
Some of the finer details (e.g., effect on lifetime and whether a _ variable can be used) differ, though.
[0]: https://github.com/cplusplus/papers/issues/878
In modern Rust you don't need the let here because you're allowed to do the pattern match anywhere, and as I said _ is simply a pattern that matches anything. So we could omit the let keyword, but people don't.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p29... aims to address that, but that won't be included until C++26 (which also includes _ as a sibling commenter mentions).
And you don't get a compilation failure when the type on the right hand side changes. This is even more important if it switches from non-drop to drop. There is a clippy lint for this.
Never thought about it, but I'll be adding this to my standard list of deny lints now.
In the case of e.g. Vec, it returns a reference, which by itself is side-effect free, so the compiler will always optimize it. I do agree that it should still be marked as such though. I'd be curious the reasons why it's not.
I think there's a reasonable position to take that it was/is too conservative, and also one that it's fine.
Index returns a reference:
https://doc.rust-lang.org/std/ops/trait.Index.html#:~:text=s...
If you don't use the reference it just ... disappears.
Am I missing something here?
You will find similar examples in Python, Java, C#,... and why not everyone is so keen into jumping new language versions.
Returns a reference to the value that is mapped to a key equivalent to key or x respectively, performing an insertion if such key does not already exist.
Which is a bit of a surprise coming from mostly C and Go.
Qt containers do it better: upsert with insert() and retrieve with value(), which, in the not found case, will return a default-constructed value (or a caller-supplied value) but without inserting it into the map.
Add an opt-in compiler flag --edition='26' which, when used, applies the breaking changes defined for C++26. Then users like Google or others who have been (ab)using some features for their side effects can decide to stay on the older versions.
https://github.com/ziglang/zig/issues/219
Languages like D [0] or Rust [1] get this right.
[0]: https://dlang.org/spec/operatoroverloading.html#index_assign... [1]: https://doc.rust-lang.org/std/ops/trait.IndexMut.html
I find it annoying that I often have to reach to defaultdict in Python to get this behavior.
It really depends on what you got used to. C++ was the first language, which, I would say, learned. I’m still surprised to day that traversing a set is not in order by default.
In this specific case, emplace should be your default option, and you should really know why that’s the case, and why you have this many options.
try { f(p.get()); (void)p.release(); } catch (...) { /* f threw; don't release p after all */ }
Many of the uses are in Google’s codebase.
Overall very technical- interesting if you are a library writer or maybe if you care about long term improvements in your C++’legacy codebase.
But alas, existing code is considered sacred in the C++ cult so we must never ever inconvenience anyone maintaining legacy code, no matter how broken it is.