digitalmars.D - "I told you so": noreturn sucks a leech and has virtually no utility
- Andrei Alexandrescu (18/18) Oct 15 2021 It has been predicted by several folks that noreturn has very limited
- Dennis (12/16) Oct 15 2021 Reference? I'm looking back at the DIP 1034 threads:
- Kagamin (1/1) Oct 15 2021 Hm? Isn't it a backend feature? How it complicates the language?
- MoonlightSentinel (3/4) Oct 15 2021 DIP 1034 proposed a bottom type named `noreturn`, not C++
- Basile B. (7/8) Oct 15 2021 No, you can use it everywhere a Type can be used: cast to type,
- Timon Gehr (3/8) Oct 15 2021 I don't think rejecting everything that's "obviously not useful" is the
- Stefan Koch (16/25) Oct 15 2021 Seconded. The point of noreturn is precisely to reject less.
- Paul Backus (16/31) Oct 15 2021 It *shouldn't* be undefined behavior. What `noreturn` means is,
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (5/9) Oct 15 2021 If we ignore the DIP, couldn't you just as well claim that you
- Paul Backus (8/17) Oct 16 2021 Even if you, the programmer, could make such assumptions, the
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (7/13) Oct 16 2021 This would make sense if you made the claim "arbitrary type" and
- MoonlightSentinel (6/10) Oct 15 2021 That's actually not the intention of the DIP, only a few usages
- MoonlightSentinel (29/50) Oct 15 2021 This is a claim that has yet to be seen. Most of the
- Dennis (36/40) Oct 15 2021 Some context for this: On February 16 this year, Mike Parker
- Dukc (33/51) Oct 15 2021 It does have teething problems, yes. But I still think the
- H. S. Teoh (9/13) Oct 15 2021 Besides its weird name (it's really a bottom type than anything else;
- Timon Gehr (19/32) Oct 15 2021 - What's in DMD is an incomplete implementation of DIP 1034, often
- H. S. Teoh (18/37) Oct 15 2021 That's unfortunate, but I suppose better than the worst scenario Andrei
- Paul Backus (7/13) Oct 15 2021 Unfortunately, the "statement is unreachable" warning cannot tell
- Imperatorn (2/16) Oct 16 2021 Yes. Many other languages take that approach
- Andrei Alexandrescu (7/7) Oct 15 2021 After skimming the DIP, I must apologize for being hasty.
It has been predicted by several folks that noreturn has very limited utility and a variety of weird corner cases that will cause a hecatomb of complications in the language, the standard library, and the implementation. (For starters: how the hell is "will not return" a type that's supposed to do all or at least most things that types do, when even the phrase defining it has no subject? It's about a FUNCTION that won't return, so it should be an attribute applicable to a FUNCTION!) In spite of these voices of reason, noreturn proceeded with a definition and implementation as expected: execrable. I was looking today through the wretched isAutodecodableString (how did we ever think /that/ was a good idea?) and found a number of weird occurrences of noreturn. Where? Of course, where you least expect or want it. Thirty-seven `noreturn` occurrences in phobos. Ten opened bugs. This is literally why we can't have nice things. If all that investment went to literally any other proposal, it would be a net positive.
Oct 15 2021
On Friday, 15 October 2021 at 17:13:29 UTC, Andrei Alexandrescu wrote:It has been predicted by several folks that noreturn has very limited utility and a variety of weird corner cases that will cause a hecatomb of complications in the language, the standard library, and the implementation.Reference? I'm looking back at the DIP 1034 threads: [Review round 1 - Discussion](https://forum.dlang.org/post/ooofastmtzmuylnjesyl forum.dlang.org) [Review round 1 - Feedback](https://forum.dlang.org/post/arcpszmdarekxtnsnwfl forum.dlang.org) [Final review - Discussion](https://forum.dlang.org/post/heylgwkzcpfqmqytiezq forum.dlang.org) [Final review - Feedback](https://forum.dlang.org/post/ceicwtqcalmgiteudkjd forum.dlang.org) I don't see it there.
Oct 15 2021
Hm? Isn't it a backend feature? How it complicates the language?
Oct 15 2021
On Friday, 15 October 2021 at 18:28:37 UTC, Kagamin wrote:Hm? Isn't it a backend feature? How it complicates the language?DIP 1034 proposed a bottom type named `noreturn`, not C++ `[[noreturn]]`.
Oct 15 2021
On Friday, 15 October 2021 at 18:28:37 UTC, Kagamin wrote:Hm? Isn't it a backend feature? How it complicates the language?No, you can use it everywhere a Type can be used: cast to type, TemplateTypeParameter, VarDeclaration type, etc. And most of the time this is obviously not useful and has to be rejected, i.e during the semantic, i.e by the front-end. So far this is not enirely done, which creates cases of ICE in the backend.
Oct 15 2021
On 10/15/21 8:52 PM, Basile B. wrote:No, you can use it everywhere a Type can be used: cast to type, TemplateTypeParameter, VarDeclaration type, etc. And most of the time this is obviously not useful and has to be rejected, i.e during the semantic, i.e by the front-end.I don't think rejecting everything that's "obviously not useful" is the right approach. It just causes headaches for generic code.
Oct 15 2021
On Friday, 15 October 2021 at 18:59:55 UTC, Timon Gehr wrote:On 10/15/21 8:52 PM, Basile B. wrote:Seconded. The point of noreturn is precisely to reject less. The no-return type has no values which means reading or writing that type is merely undefined behavior. It doesn't have to be rejected. void x; // special cased to be rejected. noreturn x; // totally fine, just don't read or write to it. with noreturn (and removing void/ or replacing it with unit) the statement any type may be used to create a variable of that type is true. Leading to less special casing and possible contradictions in the type system. How the backend may deal with a variable such as this, is actually easy. just ignore it. It doesn't need any storage and will never be referenced in well formed code.No, you can use it everywhere a Type can be used: cast to type, TemplateTypeParameter, VarDeclaration type, etc. And most of the time this is obviously not useful and has to be rejected, i.e during the semantic, i.e by the front-end.I don't think rejecting everything that's "obviously not useful" is the right approach. It just causes headaches for generic code.
Oct 15 2021
On Friday, 15 October 2021 at 19:10:42 UTC, Stefan Koch wrote:On Friday, 15 October 2021 at 18:59:55 UTC, Timon Gehr wrote:It *shouldn't* be undefined behavior. What `noreturn` means is, "evaluation of this expression does not terminate normally". Some examples of `noreturn` expressions include: - `assert(0)` - `throw new Exception("error")` - `{ while (1) {} }()` The meaning of any *specific* `noreturn` expression is determined by the semantic rules given for that expression in the language spec--i.e., it is done on a case-by-case basis. In the case of accessing a `noreturn` variable, the relevant semantic rule is given [in DIP 1034][1]: evaluating an expression that reads or writes a variable of type `noreturn` has the same behavior as evaluating the expression `assert(0)`. [1]: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1034.md#interaction-with-other-language-featuresOn 10/15/21 8:52 PM, Basile B. wrote:Seconded. The point of noreturn is precisely to reject less. The no-return type has no values which means reading or writing that type is merely undefined behavior. It doesn't have to be rejected.No, you can use it everywhere a Type can be used: cast to type, TemplateTypeParameter, VarDeclaration type, etc. And most of the time this is obviously not useful and has to be rejected, i.e during the semantic, i.e by the front-end.I don't think rejecting everything that's "obviously not useful" is the right approach. It just causes headaches for generic code.
Oct 15 2021
On Friday, 15 October 2021 at 19:10:42 UTC, Stefan Koch wrote:Seconded. The point of noreturn is precisely to reject less. The no-return type has no values which means reading or writing that type is merely undefined behavior. It doesn't have to be rejected.If we ignore the DIP, couldn't you just as well claim that you should be able to assume anything about a type that is never instantiated as long as the assumption does not lead to a contradiction?
Oct 15 2021
On Saturday, 16 October 2021 at 05:27:42 UTC, Ola Fosheim Grøstad wrote:On Friday, 15 October 2021 at 19:10:42 UTC, Stefan Koch wrote:Even if you, the programmer, could make such assumptions, the compiler cannot, because proving that a type is never instantiated is halting-equivalent. `noreturn`, on the other hand, is defined in the language spec to be impossible to instantiate, so the compiler does not need to prove anything.Seconded. The point of noreturn is precisely to reject less. The no-return type has no values which means reading or writing that type is merely undefined behavior. It doesn't have to be rejected.If we ignore the DIP, couldn't you just as well claim that you should be able to assume anything about a type that is never instantiated as long as the assumption does not lead to a contradiction?
Oct 16 2021
On Saturday, 16 October 2021 at 13:40:23 UTC, Paul Backus wrote:Even if you, the programmer, could make such assumptions, the compiler cannot, because proving that a type is never instantiated is halting-equivalent.This would make sense if you made the claim "arbitrary type" and "any possible program", but this is not what I meant.`noreturn`, on the other hand, is defined in the language spec to be impossible to instantiate, so the compiler does not need to prove anything.No, I meant, if you inject a "noreturn" type into generic code; Then you know that it will never be instantiated and could allow any assumptions about it to be true as long as the complete set of "granted" assumptions does not lead to a contradiction.
Oct 16 2021
On Friday, 15 October 2021 at 18:52:31 UTC, Basile B. wrote:No, you can use it everywhere a Type can be used: cast to type, TemplateTypeParameter, VarDeclaration type, etc. And most of the time this is obviously not useful and has to be rejected, i.e during the semantic, i.e by the front-end.That's actually not the intention of the DIP, only a few usages of `noreturn` are treated as an compiler error. E.g. `noreturn var` is fine as long as the code never accesses the variable - which is useful for templated code like `auto foo = possiblyNoreturnFunc()`.
Oct 15 2021
On Friday, 15 October 2021 at 17:13:29 UTC, Andrei Alexandrescu wrote:It has been predicted by several folks that noreturn has very limited utility and a variety of weird corner cases that will cause a hecatomb of complications in the language, the standard library, and the implementation.This is a claim that has yet to be seen. Most of the complications stem from the fact that the introduction of `noreturn` allows DMD to detect unreachable code more accurately. This caused several `statement not reachable` warnings in Phobos (and other libraries) because templated functions are now inferred as `noreturn` instead of `void`. But that problem is not specific to `noreturn` and instead a general issue for templated code.(For starters: how the hell is "will not return" a type that's supposed to do all or at least most things that types do, when even the phrase defining it has no subject? It's about a FUNCTION that won't return, so it should be an attribute applicable to a FUNCTION!)The name is misleading, `noreturn` represents the bottom type in general. But arguing about `noreturn` vs. `Nothing` vs. `<your choice here>` is just bikeshedding.In spite of these voices of reason, noreturn proceeded with a definition and implementation as expected: execrable. [...] Ten opened bugs.The DIP is actually rather precise in it's definition and reasoning. The implementation included in the current release is incomplete and in a pretty bad state. Walter started implementing some very specific basics (e.g. `noreturn exit()`) and left of without adding tests for the examples / requirements specified by the DIP (many of them are rejected or crash dmd). This is especially problematic because `noreturn` was introduced without a `-preview` flag. But at least the next release should be a lot better, I've already fixed several of the aforementioned issues and proposed an implementation for the missing aspects of that DIP.I was looking today through the wretched isAutodecodableString (how did we ever think /that/ was a good idea?) and found a number of weird occurrences of noreturn. Where? Of course, where you least expect or want it.That one is indeed nasty but mostly stems from the fact that `isAutodecodableString` accepts any type convertible to `[d]char[]` (except static arrays for some reason). That traits is a decent example of an overly general implementation.This is literally why we can't have nice things. If all that investment went to literally any other proposal, it would be a net positive.This exaggeration is wrong and definitely uncalled for
Oct 15 2021
On Friday, 15 October 2021 at 17:13:29 UTC, Andrei Alexandrescu wrote:Thirty-seven `noreturn` occurrences in phobos. Ten opened bugs.Some context for this: On February 16 this year, Mike Parker informed me that [DIP1034](dlang.org/dips/1034) was accepted and we were discussing the implementation at that time.Do you plan to implement the feature or should I hand this off to Andrew & Razvan to oversee it?A fews days later, the first PR appeared by Walter, [DIP1034: add typeof(*null)](https://github.com/dlang/dmd/pull/12209). From this it looked like Walter was going to take care of it, so that conversation ended there. However, after implementing `noreturn exit()` through his favorite style of incremental improvements, Walter abandoned it, leaving DIP1034 in like a <10% implemented state. No thorough testing, no specification, no `throw` expressions, no `typeof([])`, no new `typeof(null)`, no core.demangle support, etc. Then a new dmd release came, which included the new `noreturn` type in object.d without any preview switches, but still totally unfinished. Of course bug reports were going to come. Later, other people (among which MoonlightSentinel) started picking up the loose ends by chasing down those bugs. They stumbled on the misfeature that is 'warnings', particularly the "statement not reachable" one. The compiler became smarter about unreachable code, e.g. `case X: exit(); break;` now generates a warning about the unreachable `break` statement. These warnings also manifest in some of Phobos' generic code, and since some people compile with `-w` which treats warnings as errors, this spawned some special case `static if` for `noreturn`. IMO it's better to get rid of that awful warning (at the very least in generic code) so those cases can be removed. I haven't looked too deep at `isAutodecodableString`, but it may say more about auto decoding than `noreturn`. There's already this ugly signature: ``` void popFront(T)(scope ref inout(T)[] a) safe pure nothrow nogc if (!isAutodecodableString!(T[]) && !is(T[] == void[])) ```
Oct 15 2021
On Friday, 15 October 2021 at 17:13:29 UTC, Andrei Alexandrescu wrote:It has been predicted by several folks that noreturn has very limited utility and a variety of weird corner cases that will cause a hecatomb of complications in the language, the standard library, and the implementation.It does have teething problems, yes. But I still think the concept itself is sound.(For starters: how the hell is "will not return" a type that's supposed to do all or at least most things that types do, when even the phrase defining it has no subject? It's about a FUNCTION that won't return, so it should be an attribute applicable to a FUNCTION!)Wrong by a kilometer. It is supposed to be a bottom type - the subtype of all other types that can be referenced but never instantiated. Marking functions as not returning is only one use for it. It's also used to mark a pointer as always null, or a range or a container as always empty. Now granted, the name may lead to think otherwise. But I don't think it's any stranger than, say `const` that really means "read only" in D.In spite of these voices of reason, noreturn proceeded with a definition and implementation as expected: execrable.Excepted? Yes. But because of the youth of the feature, not because of a bad concept. Compare `noreturn` to rest of the language in 2009 or so, then it's likely to be a fair comparison.I was looking today through the wretched isAutodecodableString (how did we ever think /that/ was a good idea?) and found a number of weird occurrences of noreturn. Where? Of course, where you least expect or want it.It kind of makes sense, save for autodecoding existing in first place. Autodecoding is supposed to apply on arrays of elements that convert to characters, and `noreturn` does. Theoretically, it does not matter whether `noreturn[]` decodes or no, because it's always empty anyway. In practice special casing it to not decode was probably the easiest way to fix the resulting compile errors, plus now `isRandomAccessRange!(noreturn[]) == true`This is literally why we can't have nice things. If all that investment went to literally any other proposal, it would be a net positive.Redirecting the effort to the worst DIPs would not have been even close to net positive. There have been proposals that would have left language in _worse_ state than before even after stabilizing. You may be right that this one brings only trivial benefits, but it is far from a net negative. You might convince me that even sound new features in the reviews should have larger benefits. But this one has already gone through the reviews and implementation, and is being stabilized all the time. Plus it fits nicely in the language once stable. I say it's worth it's weight to keep from now on.
Oct 15 2021
On Fri, Oct 15, 2021 at 01:13:29PM -0400, Andrei Alexandrescu via Digitalmars-d wrote:It has been predicted by several folks that noreturn has very limited utility and a variety of weird corner cases that will cause a hecatomb of complications in the language, the standard library, and the implementation.Besides its weird name (it's really a bottom type than anything else; calling it noreturn is somewhat misleading), what exactly is wrong with it? T -- A mathematician learns more and more about less and less, until he knows everything about nothing; whereas a philospher learns less and less about more and more, until he knows nothing about everything.
Oct 15 2021
On 10/15/21 11:48 PM, H. S. Teoh wrote:On Fri, Oct 15, 2021 at 01:13:29PM -0400, Andrei Alexandrescu via Digitalmars-d wrote:- What's in DMD is an incomplete implementation of DIP 1034, often resulting in ICEs. - It gives more static information to the compiler, exacerbating the issue of dead code warnings in generic code. - Existing template constraints sometimes don't deal with the new type correctly. - It implicitly converts to everything, so you can have ambiguous overloads: ```d void foo(int x){ } void foo(string x){ } void main(){ foo(assert(0)); } ``` I suspect that's ultimately the underlying issue why isInputRange!(noreturn[]) was false. (noreturn[] was treated as an autodecodable string due to some questionable design decisions in Phobos, but then it was not clear which overload of `decode` to use. Is `noreturn[]` encoded in utf-8 or utf-16? The answer is both.)It has been predicted by several folks that noreturn has very limited utility and a variety of weird corner cases that will cause a hecatomb of complications in the language, the standard library, and the implementation.Besides its weird name (it's really a bottom type than anything else; calling it noreturn is somewhat misleading), what exactly is wrong with it? T
Oct 15 2021
On Sat, Oct 16, 2021 at 12:15:35AM +0200, Timon Gehr via Digitalmars-d wrote: [...]- What's in DMD is an incomplete implementation of DIP 1034, often resulting in ICEs.That's unfortunate, but I suppose better than the worst scenario Andrei first thought. :-P- It gives more static information to the compiler, exacerbating the issue of dead code warnings in generic code.But shouldn't dead code in generic code just be elided, instead of eliciting warnings?- Existing template constraints sometimes don't deal with the new type correctly. - It implicitly converts to everything, so you can have ambiguous overloads: ```d void foo(int x){ } void foo(string x){ } void main(){ foo(assert(0)); } ```Haha, unexpected interactions with a new feature: the plague of every language designer. :-DI suspect that's ultimately the underlying issue why isInputRange!(noreturn[]) was false. (noreturn[] was treated as an autodecodable string due to some questionable design decisions in Phobos, but then it was not clear which overload of `decode` to use. Is `noreturn[]` encoded in utf-8 or utf-16? The answer is both.)I think I can guess the cause of this one. Phobos checks for implicit conversion to dchar, which before the advent of noreturn applied only to char, wchar, and dchar. But now noreturn comes along and implicit converts to everything, so the sig constraint incorrectly thinks that it must be one of the char types. Past this point, it becomes a train wreck as noreturn crashes through code that was expecting char, wchar, and dchar but getting noreturn instead. T -- If the comments and the code disagree, it's likely that *both* are wrong. -- Christopher
Oct 15 2021
On Saturday, 16 October 2021 at 02:56:02 UTC, H. S. Teoh wrote:On Sat, Oct 16, 2021 at 12:15:35AM +0200, Timon Gehr viaUnfortunately, the "statement is unreachable" warning cannot tell the difference between generic code and non-generic code, and has thus far resisted all attempts to teach it. Personally I think removing it altogether would be a net gain for the language. If anyone really wants it, we can always implement it as a check in D-Scanner or some similar tool.- It gives more static information to the compiler, exacerbating the issue of dead code warnings in generic code.But shouldn't dead code in generic code just be elided, instead of eliciting warnings?
Oct 15 2021
On Saturday, 16 October 2021 at 04:04:29 UTC, Paul Backus wrote:On Saturday, 16 October 2021 at 02:56:02 UTC, H. S. Teoh wrote:Yes. Many other languages take that approachOn Sat, Oct 16, 2021 at 12:15:35AM +0200, Timon Gehr viaUnfortunately, the "statement is unreachable" warning cannot tell the difference between generic code and non-generic code, and has thus far resisted all attempts to teach it. Personally I think removing it altogether would be a net gain for the language. If anyone really wants it, we can always implement it as a check in D-Scanner or some similar tool.- It gives more static information to the compiler, exacerbating the issue of dead code warnings in generic code.But shouldn't dead code in generic code just be elided, instead of eliciting warnings?
Oct 16 2021
After skimming the DIP, I must apologize for being hasty. By just looking at the bugs posted and the Phobos changes, it seemed to me (wrongly, fortunately) that noreturn has had an incomplete definition and was sprawling as corner cases were discovered. Whereas there may be valid concerns with regard to its usefulness, at the very minimum any critique would need to debate the definition laid down in the DIP with laudable care.
Oct 15 2021