Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

For the Rust inclined, [[nodiscard]] is #[must_use], if you were confused.

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++.

Totally agree it should be marked as nodiscard, and the reasoning for not doing so is a good example of why other languages are taking over.



I'm not a fan of nodiscard because it's applied way too freely, even if the return value is not relevant. E.g. WebGPU/WGSL initially made atomics nodiscard simply because they return a value, but half the algorithms that use atomics only do so for the atomic write, without needing the return value. But due to nodiscard you had to make a useless assignment to an unused variable.


Disagree. This is the default in Objective-C & Swift, and it’s great. You have to explicitly annotate when discards are allowed. It’s probably my all time favorite compiler warning in terms of accidental-bugs-caught-early, because asking the deeper question about why a function returns useless noise invites deep introspection.


It’s also worth noting that in rust you don’t need to be as worried about marking a function #[must_use] if there is a valid reason some of the time to discard the value. One can just assign like so `let _ = must_use_fn()` which discards the value and silences the warning. I think this makes the intent more clear than casting to void as TFA discusses.


There is in c++, too (std::ignore). Not sure why the author decided to go with the ancient void cast


std::ignore's behavior outside of use with std::tie is not specified in any finalized standard.

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).


I believe C++26 now allows _ as a placeholder name [0]:

> 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


Specifically, Rust's _ is not a variable, it is a pattern that matches anything and so let _ = isn't an assignment it's specifically the explicit choice not to assign this value. If we wrote a "dummy" variable the compiler is forbidden from dropping the value early, that "dummy" is alive until it leaves scope, whereas if we never assigned the value it's dropped immediately.

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://quuxplusone.github.io/blog/2022/10/16/prefer-core-ov... does not (yet) include this as one of its examples, but it could (and someday might).


Careful. I don't like the use of `let _ =` in general, as it instantly drops.

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.


Good point. You can always explicitly type the underscore. Clippy even has `let_underscore_untyped` for this.

Never thought about it, but I'll be adding this to my standard list of deny lints now.


I disagree with the conclusion, other languages are taking over because they have the advantage of not having 40 years of production code history, and those adopting them don't care about existing code.

You will find similar examples in Python, Java, C#,... and why not everyone is so keen into jumping new language versions.


Interestingly Index::index is also usually not marked as `#[must_use]` in Rust either.


I don't believe you can mark trait methods with #[must_use] - it has to be on the implementation. Not near a compiler to check at the moment.

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.


This is just my take, but I think historically the Rust team was hesitant to over-mark things #[must_use] because they didn't want to introduce warning fatigue.

I think there's a reasonable position to take that it was/is too conservative, and also one that it's fine.


But it's also not marked at the implementation for HashMap's Index impl for instance.


This didn't seem like a footgun to me, hats["Jim"]; will panic if, in fact "Jim" isn't one of the keys, but what did the hypothetical author expect to happen when they write this? HashMap doesn't implement IndexMut so hats["Jim"] = 26; won't even compile.


Unsure if I misunderstand:

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?


Technically without any optimizations this would result in a stray LEA op or something but any optimizing compiler (certainly any that support Rust) would optimize it out even at low levels of debug settings.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: