DIP 1038: @nodiscard - Unofficial "post-final" review
Paul Backus
snarwin at gmail.com
Mon Feb 22 23:32:23 UTC 2021
On Monday, 22 February 2021 at 22:01:01 UTC, Andrei Alexandrescu
wrote:
>
> This is nice and well argued. The time-tested presence of the
> attribute in C++ is important, probably could use 1-2
> paragraphs to emphasize that. (It's been a non-standard
> extension for a long time and clearly there was a lot of demand
> to standardize it.)
Are there any well-known [[nodiscard]] success stories that the
DIP could cite? I have little personal experience with C++, and
do not know where to look for examples outside of the standard
library.
> For integration, it would be nice if the proposal made pure
> non-void functions automatically nodiscard. That way ignoring
> the reusult of such a function is an error, as it should.
The compiler currently issues a warning when the return value of
a strongly-pure, nothrow, non-void function is discarded. I agree
that there is a case to be made that this should be an error
instead, but I think the appropriate place to make that case is
in an enhancement request on Bugzilla, not DIP 1038.
> The proposal should mention what happens if two declararions
> differ only by nodiscard:
>
> void* malloc(size_t);
> @nodiscard void* malloc(size_t);
>
> I forgot what we usually do. I think it's safe to mark that as
> as error.
@nodiscard is a user-defined attribute, and the compiler
currently allows multiple declarations of a function that differ
only by UDAs. [1] Again, I agree that this should probably be an
error, but since it is an issue that affects UDAs in general, it
should be addressed in a Bugzilla issue, not DIP 1038.
> The proposal should mention how @nodiscard works with
> overriding. Given that @nodiscard is more restrictive, by the
> old OOP principles a @nodiscard function should be overridable
> by a non- at nodiscard function. (Rationale: overriding functions
> ASK LESS and RETURN MORE.) However, a practicality
> consideration is that the author of the override simply forgot
> to add @nodiscard, so we can make the attribute equivariant.
> It's important in all cases that a no- at nodiscard function
> cannot be overriden by a @nodiscard one.
@nodiscard is a UDA, and UDAs are not inherited, so applying
@nodiscard to a base-class method will have no affect on
derived-class methods that override it.
The way to achieve the outcome you desire here is to apply
@nodiscard to the method's return type, rather than the method
itself:
@nodiscard struct Result { int unwrap; }
class A { Result func() { return Result(1); } }
class B : A { override Result func() { return Result(2); } }
The idea behind the proposed design is that if you want strong
guarantees, you should be applying @nodiscard to your types, not
to your functions. If you are willing to accept weaker guarantees
in return for greater ease-of-use, that's when you should use
@nodiscard as a function attribute. (This design is cribbed from
Rust's `#[must_use]` attribute, which works the same way.)
Of course, the fact we're having this exchange means that the
above explanation really ought to be in the DIP itself.
Thanks for your comments!
[1] https://run.dlang.io/is/tK14gJ
More information about the Digitalmars-d
mailing list