July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sunday, 9 July 2017 at 14:43:20 UTC, Andrei Alexandrescu wrote:
> On 07/09/2017 10:10 AM, Steven Schveighoffer wrote:
>> I haven't seen another solution other than out { assert(0); }
>
> Your own comment takes it to the recycle bin:
>
>> The one disadvantage, is that -release removes contracts. So in this
>> particular case, the out contract should remain.
>
> That's already a hack on top of a hack.
An out contract should apply even when contracts are removed. The compiler can treat it as not returning even if contracts are removed. But the compiler could in this case leave the contract in as a stop gap in case the function does return.
I fact it's fine if it doesn't. It will just be UB.
It's no more of a hack than leaving assert(0) in release code.
-Steve
|
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 07/09/2017 12:19 PM, Steven Schveighoffer wrote:
> It's no more of a hack than leaving assert(0) in release code.
I wouldn't argue that. I do argue it's a hack compared to the principled solution of a bottom type. -- Andrei
|
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sunday, 9 July 2017 at 18:01:08 UTC, Andrei Alexandrescu wrote:
> On 07/09/2017 12:19 PM, Steven Schveighoffer wrote:
>> It's no more of a hack than leaving assert(0) in release code.
>
> I wouldn't argue that. I do argue it's a hack compared to the principled solution of a bottom type. -- Andrei
Adding a new builtin-type would also be okay.
But a compiler-recognized custom structs is quite costly and brings with it a much higher complexity and more importantly a higher compile-time cost.
It would also require yet another symbol in object.d which is too big as it is.
|
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 07/08/2017 02:37 PM, Andrei Alexandrescu wrote:
> nice touch of bottom (heh)
Where's D's PC-police now?
|
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 07/08/2017 08:17 AM, Andrei Alexandrescu wrote:
> On 7/8/17 6:15 AM, Walter Bright wrote:
>> Has anyone a better idea? Does anyone want to write a DIP for this?
>
> An attribute is fine. A more PL-minded possibility is to return a specific type:
>
> struct None
> {
> @disable this();
> @disable this(this);
> @disable @property None init();
> }
>
> None ThisFunctionExits();
>
> The compiler detects (without having anything hardwired about the particular type "None") that the type None is impossible to create and copy/move from a function, and therefore decrees the function will never return.
Pro:
- Having the indication "this doesn't return" syntactically be the return type makes a lot of sense. I like that a lot. (Though I'd have no objection to Walter's original suggestion either).
- It's one less built-in @attribute to scare people away with objections of "too many attributes"! (And admittedly, idiomatic D can end up with lots of attribtes all over the place.)
Con:
- Inferring that a type is meant to indicate "functions 'returning' this do not return", strikes me as very round-about, hackish, unintuitive and just unclean.
I really think this is one case where a dedicated compiler-understood symbol is not only fully justified but also much cleaner.
That would be my #1 top preference: Your suggestion here, but just make "NoReturn" (or whatever it'll be called) a special compiler-understood "type", not something inferred from the detailed of a library-provided type.
In any case, I'm definitely onboard with the idea of having SOME standard way to tell the compiler "this does not return". That would be nice to have.
|
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel N | On 07/09/2017 06:51 AM, Daniel N wrote:
> On Sunday, 9 July 2017 at 10:31:47 UTC, Mr.D wrote:
>> On Saturday, 8 July 2017 at 10:15:39 UTC, Walter Bright wrote:
>>
>>> Has anyone a better idea?
>>
>> What about
>>
>> scope(exit) assert(0);
>>
>> ?
>
> void func()
> out { assert(0); }
> body
> {
> }
Too indirect and verbose. An attribute or special "return type" would just cut straight to the case.
|
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 7/9/2017 6:13 AM, Andrei Alexandrescu wrote:
> We should use typeof(assert(0)) for Bottom. There is precedent - there is no name for typeof(null).
I had forgotten about the typeof(null) thing. You're right. But there are some issues. What do we do with:
typeof(assert(0))* p;
? What does that mean?
|
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 7/9/2017 6:13 AM, Andrei Alexandrescu wrote:
> We should use typeof(assert(0)) for Bottom.
That also leaves the door open for:
alias noreturn = typeof(assert(0));
|
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sunday, 9 July 2017 at 18:01:08 UTC, Andrei Alexandrescu wrote: > On 07/09/2017 12:19 PM, Steven Schveighoffer wrote: >> It's no more of a hack than leaving assert(0) in release code. > > I wouldn't argue that. I do argue it's a hack compared to the principled solution of a bottom type. -- Andrei I thought some more about the ramifications of having a Bottom type in D. Having a special type like this interacts badly with most aspects of D's generic programming capabilities, even on the simplest level. At the least we would probably have to create special cases everywhere in the compiler and/or libraries that check if the type we're working with is the bottom type. A few simple cases I can think of off the top of my head: alias Bottom = typeof(assert(0)); //for convenience Bottom* pb; //Must be statically disallowed as this makes no sense Bottom[] ab; //ditto cast(Bottom)1; //ditto struct TupleLike(T...) { T fields; } //What now? Do we allow this type to be instantiated but never created, //as it contains Bottom? Or do we allow it to be instantiated and created, //but the program crashes at runtime when it actually attempts to create a //value of type Bottom? TupleLike!(string, int, Bottom) t; //Likewise. Either user code will have to add `if (!is(T == Bottom))` //every time they define a wrapper struct like this, or an error //would be generated from inside the aggregate the declares a `T t` //member. The former is tedious, the latter defeats the purpose //of template guards in the first place alias Bad = Nullable!Bottom; And I'm sure there are many more. We could make passing Bottom as a template argument an error, which seems reasonable to me (this is the route Rust goes, I think). Here's a few good links: https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#the-never-type--that-never-returns https://www.reddit.com/r/rust/comments/3j22vx/what_is_the_meaning_of_as_a_return_type/ https://github.com/rust-lang/rfcs/pull/1216 There's a discussion in that Reddit thread about some of the advantages/disadvantages of making Bottom a first-class type. Also a point of interest is that by adding a Bottom type to D and with a bit of fiddling we can *almost* implement `assert(0)` in library code as opposed to in the compiler: void assert(T)(lazy T cond, lazy string msg = "") if (is(typeof(cast(bool)cond)) { if (is(T == int) && cond == 0)) { //Compiles recognizes that a value of type Bottom //is being created and inserts a HLT instruction //(Or whatever it is that assert(0) does nowadays) Bottom impossible; } if (cond) return; if (msg.length) { import std.stdio; stderr.writeln(msg); } assert(0); } I say almost because there's no way in user code to detect the specific form `assert(0)` without making changes to how we call it. A user could unintentionally halt the program by doing something like `assert(m - n, "m and n should not be the same")`. It could be done with templates but it'd break user code: //`assert(0)` must now be called like `assert!0` Bottom assert(int n: 0)(lazy string msg = "") { if (msg.length) { import std.stdio; stderr.writeln(msg); } Bottom impossible; } |
July 09, 2017 Re: proposed @noreturn attribute | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Sunday, 9 July 2017 at 19:12:45 UTC, Walter Bright wrote:
> On 7/9/2017 6:13 AM, Andrei Alexandrescu wrote:
>> We should use typeof(assert(0)) for Bottom. There is precedent - there is no name for typeof(null).
> I had forgotten about the typeof(null) thing. You're right. But there are some issues. What do we do with:
>
> typeof(assert(0))* p;
>
> ? What does that mean?
Not valid.
Cannot take a pointer of typeof(assert(0)).
|
Copyright © 1999-2021 by the D Language Foundation