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