www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Discussion Thread: DIP 1038-- nodiscard--Community Review Round 1

reply Mike Parker <aldacron gmail.com> writes:
This is the discussion thread for the first round of Community 
Review of DIP 1038, " nodiscard":

https://github.com/dlang/DIPs/blob/58b29a85fdf3cbf3521235e40f2a66e141e856c2/DIPs/DIP1038.md

The review period will end at 11:59 PM ET on December 23, or when 
I make a post declaring it complete. Discussion in this thread 
may continue beyond that point.

Here in the discussion thread, you are free to discuss anything 
and everything related to the DIP. Express your support or 
opposition, debate alternatives, argue the merits, etc.

However, if you have any specific feedback on how to improve the 
proposal itself, then please post it in the feedback thread. The 
feedback thread will be the source for the review summary that I 
will write at the end of this review round. I will post a link to 
that thread immediately following this post. Just be sure to read 
and understand the Reviewer Guidelines before posting there:

https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md

And my blog post on the difference between the Discussion and 
Feedback threads:

https://dlang.org/blog/2020/01/26/dip-reviews-discussion-vs-feedback/

Please stay on topic here. I will delete posts that are 
completely off-topic.
Dec 09 2020
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 9 December 2020 at 10:10:40 UTC, Mike Parker wrote:

 However, if you have any specific feedback on how to improve 
 the proposal itself, then please post it in the feedback 
 thread. The feedback thread will be the source for the review 
 summary that I will write at the end of this review round. I 
 will post a link to that thread immediately following this post.
The Feedback Thread is located here: https://forum.dlang.org/post/qptthjobogooocleizvo forum.dlang.org
Dec 09 2020
prev sibling next sibling parent reply NotSpooky <pleasedontemailme gmail.com> writes:
What I usually do to avoid exceptions is using Nullable/Variant 
as the return type, as using it still needs checking.
So, syntax sugar to return those seems like a nicer alternative 
with less changes to the compiler and less  s
Dec 10 2020
parent Paul Backus <snarwin gmail.com> writes:
On Friday, 11 December 2020 at 03:54:53 UTC, NotSpooky wrote:
 What I usually do to avoid exceptions is using Nullable/Variant 
 as the return type, as using it still needs checking.
 So, syntax sugar to return those seems like a nicer alternative 
 with less changes to the compiler and less  s
The idea is that you will be able to mark your Nullable/Variant type as nodiscard, and the compiler will warn you if you forget to check it. Marking the type as nodiscard also means you will not have to annotate the individual functions, so in practice the number of s needed should be fairly small.
Dec 11 2020
prev sibling next sibling parent reply Guillaume Piolat <first.name guess.com> writes:
On Wednesday, 9 December 2020 at 10:10:40 UTC, Mike Parker wrote:
 This is the discussion thread for the first round of Community 
 Review of DIP 1038, " nodiscard":

 https://github.com/dlang/DIPs/blob/58b29a85fdf3cbf3521235e40f2a66e141e856c2/DIPs/DIP1038.md
So, er.... I feel in the "target market" of this DIP, we use D-with-runtime-disabled and the codebase is completely nogc. The DIP is not that appealing to me because we do manage to throw/catch anyway with manually allocated exceptions. So most likely I would put this attribute in the "do not use" list of D features. I'd be more excited about: - throw-by-value exceptions - a way to use exceptions in nogc and even -betterC (There was a DIP for it, it was implemented, but doesn't work IIRC) than improving error codes. That said, I have no real idea how much needed this DIP is.
Dec 11 2020
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 11 December 2020 at 08:03:06 UTC, Guillaume Piolat 
wrote:
 So, er.... I feel in the "target market" of this DIP
I think I'd actually use it for an entirely different purpose. My cgi.d has a function called `schedule` that returns a plan builder object but doesn't actually do anything with it. You're supposed to actually build it then commit it. Like so: schedule!some_operation.at(whatever); The nodiscard there could help when you've constructed the builder, but didn't actually do anything with it. Perhaps you'd argue a required named param or something is better here but I still kinda like this.
 - a way to use exceptions in  nogc and even -betterC (There was 
 a DIP for it, it was implemented, but doesn't work IIRC)
The -dip1008 switch.... sometimes works? i rarely use non-default switches but i had success playing with it in small toys.
Dec 11 2020
parent Guillaume Piolat <first.name guess.com> writes:
On Friday, 11 December 2020 at 14:01:59 UTC, Adam D. Ruppe wrote:
 The -dip1008 switch.... sometimes works? i rarely use 
 non-default switches but i had success playing with it in small 
 toys.
To be precise: -review=dip1008 doesn't work well with -betterC since you can't use try/catch in -betterC, it needs the equivalent of a dynamic cast, so more RTTI https://d.godbolt.org/z/Ta5T7K Curious if it works for your WASM work
Dec 11 2020
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2020-12-11 09:03, Guillaume Piolat wrote:

 So, er.... I feel in the "target market" of this DIP, we use 
 D-with-runtime-disabled
 and the codebase is completely  nogc.
 The DIP is not that appealing to me because we do manage to throw/catch 
 anyway with manually allocated exceptions.
 
 So most likely I would put this attribute in the "do not use" list of D 
 features.
 
 I'd be more excited about:
 - throw-by-value exceptions
 - a way to use exceptions in  nogc and even -betterC (There was a DIP 
 for it, it was implemented, but doesn't work IIRC)
 than improving error codes.
I completely agree. Instead of this approach, the compiler could lower try/catch/finally/throw for a function to return tagged union of the success value and all the exceptions that can be thrown. Then one could easily throw any kind of types, not just classes inheriting from `Throwable`, including value types. -- /Jacob Carlborg
Dec 11 2020
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Dec 11, 2020 at 08:54:58PM +0100, Jacob Carlborg via Digitalmars-d
wrote:
 On 2020-12-11 09:03, Guillaume Piolat wrote:
[...]
 I'd be more excited about:
 - throw-by-value exceptions
 - a way to use exceptions in  nogc and even -betterC (There was a DIP
 for it, it was implemented, but doesn't work IIRC)
 than improving error codes.
I completely agree. Instead of this approach, the compiler could lower try/catch/finally/throw for a function to return tagged union of the success value and all the exceptions that can be thrown.
Yes! Lightweight by-value exceptions will be a plus in my book.
 Then one could easily throw any kind of types, not just classes
 inheriting from `Throwable`, including value types.
[...] But I don't agree with this. I used to write a lot of C++, where you can throw literally *anything*. It seems to be a good thing to allow maximum flexibility, but that actually hinders code interoperability: you cannot assume *anything* about something you caught, because it can literally be *any* type. D's Throwable API is much better because it guarantees a minimal common interface that all catch blocks can depend on. Having a standard .msg field that returns a string you can print to the user in the event you need to abort, e.g., is much more useful than an opaque type that you can't do anything with other than say "an error occurred, abort" -- what error? Don't know, can't know, the catch block in main() has no idea where it came from or what information might be encoded within. Knowledge about the error might only exist inside a 3rd party dependency. Maximum flexibility isn't always a good thing. T -- Study gravitation, it's a field with a lot of potential.
Dec 11 2020
parent reply Jacob Carlborg <doob me.com> writes:
On 2020-12-11 21:27, H. S. Teoh wrote:

 But I don't agree with this.
 
 I used to write a lot of C++, where you can throw literally *anything*.
 It seems to be a good thing to allow maximum flexibility, but that
 actually hinders code interoperability: you cannot assume *anything*
 about something you caught, because it can literally be *any* type.  D's
 Throwable API is much better because it guarantees a minimal common
 interface that all catch blocks can depend on.  Having a standard .msg
 field that returns a string you can print to the user in the event you
 need to abort
Yeah, I've been thinking about how to best solve that. My vision extends a bit more than just a different implementation of exception handling. I want the error handling to be usable everywhere, including low level code. Ideally it should be usable without a runtime. As soon as you start requiring classes, that will impose limitations.
 e.g., is much more useful than an opaque type that you
 can't do anything with other than say "an error occurred, abort" -- what
 error? Don't know, can't know, the catch block in main() has no idea
 where it came from or what information might be encoded within.
 Knowledge about the error might only exist inside a 3rd party
 dependency.
In my vision it wouldn't be an opaque type. But it would be good to have a way to handle all errors in one place.
 Maximum flexibility isn't always a good thing.
I've been thinking about limiting the types to user defined types. I should really try to write down my ideas regarding this. -- /Jacob Carlborg
Dec 16 2020
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Dec 16, 2020 at 08:49:41PM +0100, Jacob Carlborg via Digitalmars-d
wrote:
 On 2020-12-11 21:27, H. S. Teoh wrote:
 
 But I don't agree with this.
 
 I used to write a lot of C++, where you can throw literally
 *anything*.  It seems to be a good thing to allow maximum
 flexibility, but that actually hinders code interoperability: you
 cannot assume *anything* about something you caught, because it can
 literally be *any* type.  D's Throwable API is much better because
 it guarantees a minimal common interface that all catch blocks can
 depend on.  Having a standard .msg field that returns a string you
 can print to the user in the event you need to abort
Yeah, I've been thinking about how to best solve that. My vision extends a bit more than just a different implementation of exception handling. I want the error handling to be usable everywhere, including low level code. Ideally it should be usable without a runtime. As soon as you start requiring classes, that will impose limitations.
Exceptions don't have to be classes, even though that's the most obvious way to implement it. For example, it could be a runtime-defined struct that contains the most pertinent information, with an optional polymorphic reference to additional information that people might want to transmit along with their exceptions.
 e.g., is much more useful than an opaque type that you can't do
 anything with other than say "an error occurred, abort" -- what
 error? Don't know, can't know, the catch block in main() has no idea
 where it came from or what information might be encoded within.
 Knowledge about the error might only exist inside a 3rd party
 dependency.
In my vision it wouldn't be an opaque type. But it would be good to have a way to handle all errors in one place.
It's not that the type itself is opaque, it's that since you can throw *any* arbitrary type, the catching code cannot predict in advance what the concrete type(s) the caught exception will be, and therefore it cannot make any assumptions about the type of the exception, including what operations are permitted on it. It cannot assume there's a .msg field that contains an error message, for instance, since somebody could have thrown an int. Or any type without a .msg member, for that matter.
 Maximum flexibility isn't always a good thing.
I've been thinking about limiting the types to user defined types.
[...] Even so, if there is no standard API that exceptions must implement, then you cannot write top-level catch that does something useful (beyond just printing "Error" and aborting). There must be some kind of minimum set of attributes that you can depend on, like a string .msg. Possibly also .file and .line. T -- Gone Chopin. Bach in a minuet.
Dec 16 2020
prev sibling parent Paul Backus <snarwin gmail.com> writes:
On Friday, 11 December 2020 at 19:54:58 UTC, Jacob Carlborg wrote:
 On 2020-12-11 09:03, Guillaume Piolat wrote:
 I'd be more excited about:
 - throw-by-value exceptions
 - a way to use exceptions in  nogc and even -betterC (There 
 was a DIP for it, it was implemented, but doesn't work IIRC)
 than improving error codes.
I completely agree. Instead of this approach, the compiler could lower try/catch/finally/throw for a function to return tagged union of the success value and all the exceptions that can be thrown. Then one could easily throw any kind of types, not just classes inheriting from `Throwable`, including value types.
Feel free to submit a DIP. :) My experience in the D community so far has been that large, ambitious projects tend to fail, but small, incremental improvements often succeed. If someone steps forward with a DIP and an implementation for throw-by-value exceptions (or some other improved error-handling mechanism), I'll be happy to support them, but I'm not going to be that person myself.
Dec 11 2020
prev sibling next sibling parent Robert burner Schadek <rburners gmail.com> writes:
https://forum.dlang.org/post/mloquupidedjxasqqhkt forum.dlang.org

 The only "correct" way to get to any percentage, is to try to 
 use all packages from code that is nothrow and/or  nogc.
I am well aware that these numbers are not perfectly accurate. The point of using them is only to get a rough approximation of the proportion of D code that could benefit from an alternative to exceptions. Unless there is a reason to think they are strongly *biased* (i.e., there are many more false positives than false negatives), it does not really matter to the DIP's argument if they are off by a few percent one way or the other. As you point out, the amount of work required to get more accurate data is prohibitive, so the actual choice is between "rough, approximate numbers" and "no numbers at all." I think the DIP is stronger with the numbers than without them, even accounting for their shortcomings, but I am happy to hear arguments to the contrary.
I have to disagree forcefully, no numbers are highly preferable unless you have shown that they are accurate, within a few percent. The burden of proof is on the DIP. Please read the following sympathetic. Using these false numbers to emphasize the usefulness of this DIP has the opposite effect. Every word I read after seeing these claims left a foul taste, even though I consider this a useful DIP.
Dec 11 2020
prev sibling next sibling parent Dave P. <dave287091 gmail.com> writes:
On Wednesday, 9 December 2020 at 10:10:40 UTC, Mike Parker wrote:
 This is the discussion thread for the first round of Community 
 Review of DIP 1038, " nodiscard":

 [...]
I use the equivalent feature in C all the time and it is great. It especially helps when a function that previously was declared as returning void needs to now return an error code.
Dec 11 2020
prev sibling next sibling parent Dennis <dkorpel gmail.com> writes:
On Wednesday, 9 December 2020 at 10:10:40 UTC, Mike Parker wrote:
 This is the discussion thread for the first round of Community 
 Review of DIP 1038, " nodiscard":
This is a reply to Andrej Mitrovic's post in the Feedback Thread. https://forum.dlang.org/post/gdjclwuwuoyqiftdercu forum.dlang.org
 I think  nodiscard should not apply to void functions.
 (...)
 At least I can't think of use-cases for it having an effect on 
 void functions.
There is a pattern that replaces `goto fail;` and `goto success;` style error handling with calls to (inner) functions in a return statement. It looks something like this: ``` struct Parser { S result; string error; void setError(string msg) { error = msg; } void parse(string s) { if (s.length == 0) { return setError("empty input"); } if (!s.starsWith("MAGIC")) { return setError("wrong header"); } // etc. } } ``` This pattern is used in dmd: https://github.com/dlang/dmd/blob/97aa2ae5ee19ce6a2979ca1627479df713f99252/src/dmd/expressionsem.d#L2524 https://github.com/dlang/dmd/blob/97aa2ae5ee19ce6a2979ca1627479df713f99252/src/dmd/expressionsem.d#L5383 Functions setError() yes() and no() should be called in a return statement, continuing afterwards could be considered a bug. One might want to apply nodiscard to those functions so it will be caught by the compiler when you forget to prepend `return`. For that to work however, nodiscard should not have a special case for `void`.
Dec 14 2020
prev sibling parent reply RazvanN <razvan.nitu1305 gmail.com> writes:
On Wednesday, 9 December 2020 at 10:10:40 UTC, Mike Parker wrote:
 This is the discussion thread for the first round of Community 
 Review of DIP 1038, " nodiscard":

 [...]
Mike, it seems that this DIP is past its first community review. Should it not advance to the next round?
Jan 08
parent Mike Parker <aldacron gmail.com> writes:
On Friday, 8 January 2021 at 10:50:39 UTC, RazvanN wrote:
 On Wednesday, 9 December 2020 at 10:10:40 UTC, Mike Parker 
 wrote:
 This is the discussion thread for the first round of Community 
 Review of DIP 1038, " nodiscard":

 [...]
Mike, it seems that this DIP is past its first community review. Should it not advance to the next round?
Not yet. There are other DIPs ahead in the queue.
Jan 08