proposed @noreturn attribute

Meta via Digitalmars-d digitalmars-d at puremagic.com
Sun Jul 9 12:30:25 PDT 2017


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;
}


More information about the Digitalmars-d mailing list