Built-in sumtypes, case and noreturn: why block enders should be expressions.

Dukc ajieskola at gmail.com
Wed Oct 26 12:07:41 UTC 2022


On Wednesday, 26 October 2022 at 05:53:21 UTC, FeepingCreature 
wrote:
>> ```D
>> extern(C) Throwable abort();
>> noreturn foo() nothrow { throw abort; }
>> ```
>>
>> ...which I believe currently works. Or is that a problem too?
>
> That doesn't work. How would it? D has no idea that abort can 
> never return if it's not typed `noreturn`. (Neither works, to 
> be clear.)

Just tested. Yes, it doesn't work. This does, though:

```D
extern(C) Error abort();
noreturn foo() nothrow { throw abort; }
```

It works because a throw statement is always of type `noreturn`, 
no matter what is thrown. If `abort` indeed aborts, fine, 
obviously we don't return. However, if it did return an `Error`, 
we'd then throw that, which also prevents doing anything with 
"result" of `throw`. This works even in `nothrow` because we're 
throwing an unrecoverable error, not an exception. This is also 
why the snippet with `Throwable` does not compile - `abort` might 
potentially return an `Exception`, because `Exception`s are 
`Throwable`s. With an `Error` return type, that's not possible.

It makes an interesting question whether `throw throw something` 
(or `throw assert(0)`) should be allowed, and if, should it be 
`@safe` and/or `nothrow`? You could argue that the bottom type 
converts to `Exception` and thus you can't do it in `nothrow`, 
but can in `@safe`. Equally you could say the bottom type 
converts to `Error`, so throwing it should be ok in `nothrow` but 
not in `@safe`. Or you could say that since the execution will 
never actually reach where a bottom type is instantiated, it's ok 
to "throw" it anywhere.


More information about the Digitalmars-d mailing list