January 17, 2022
On Monday, 17 January 2022 at 16:11:03 UTC, Timon Gehr wrote:
> In D, types that do not have a default constructor cannot be default-constructed. The question is whether `noreturn`, the empty type, should really have a default constructor (that immediately terminates the program). As far as I understand, according to the DIP, `noreturn` has a default constructor, but `noreturn` variables are initialized lazily when they are accessed.

I think the best way to describe the behavior specified by the DIP is that the compiler rewrites

    noreturn x;

to

    noreturn x = void;

So, there is a special case here, but it does not require noreturn to have a default constructor.
January 17, 2022
On Mon, Jan 17, 2022 at 05:57:19PM +0000, Paul Backus via Digitalmars-d wrote:
> On Monday, 17 January 2022 at 16:11:03 UTC, Timon Gehr wrote:
> > In D, types that do not have a default constructor cannot be default-constructed. The question is whether `noreturn`, the empty type, should really have a default constructor (that immediately terminates the program). As far as I understand, according to the DIP, `noreturn` has a default constructor, but `noreturn` variables are initialized lazily when they are accessed.
> 
> I think the best way to describe the behavior specified by the DIP is that the compiler rewrites
> 
>     noreturn x;
> 
> to
> 
>     noreturn x = void;
> 
> So, there is a special case here, but it does not require noreturn to have a default constructor.

The question then would be, why such a special case?  There's no need to have a special case here, since aborting/terminating on declaring a variable of type noreturn is perfectly reasonable semantics for a bottom type.


T

-- 
What is Matter, what is Mind? Never Mind, it doesn't Matter.
January 17, 2022
On Mon, Jan 17, 2022 at 05:53:25PM +0000, Elronnd via Digitalmars-d wrote:
> On Monday, 17 January 2022 at 16:11:03 UTC, Timon Gehr wrote:
> > if a type `A*` is a subtype of a type `B*`, then `A.sizeof>=B.sizeof`.  `noreturn*` is a subtype of any `T*`. Hence, `noreturn.sizeof` should be at least `size_t.max` or even `∞`.
> 
> I don't think this is right; it must be that A.sizeof==B.sizeof. Consider e.g.:
> 
> B* f(B* b) { return b+1; }
> 
> What happens if you pass in an A*, and A.sizeof>B.sizeof?

This is exactly what happens when you pass a derived class to a function that expects the base class, BTW.


T

-- 
The problem with the world is that everybody else is stupid.
January 17, 2022
On Monday, 17 January 2022 at 18:05:10 UTC, H. S. Teoh wrote:
> On Mon, Jan 17, 2022 at 05:57:19PM +0000, Paul Backus via Digitalmars-d wrote:
>> 
>> I think the best way to describe the behavior specified by the DIP is that the compiler rewrites
>> 
>>     noreturn x;
>> 
>> to
>> 
>>     noreturn x = void;
>> 
>> So, there is a special case here, but it does not require noreturn to have a default constructor.
>
> The question then would be, why such a special case?  There's no need to have a special case here, since aborting/terminating on declaring a variable of type noreturn is perfectly reasonable semantics for a bottom type.

Both the rewrite I describe and the behavior you propose are special cases. The non-special-case behavior is "compile-time error."
January 17, 2022
On Monday, 17 January 2022 at 18:05:49 UTC, H. S. Teoh wrote:
>> What happens if you pass in an A*, and A.sizeof>B.sizeof?
>
> This is exactly what happens when you pass a derived class to a function that expects the base class, BTW.

You can't do pointer arithmetic on class instances.
January 17, 2022
On Mon, Jan 17, 2022 at 06:11:09PM +0000, Paul Backus via Digitalmars-d wrote:
> On Monday, 17 January 2022 at 18:05:10 UTC, H. S. Teoh wrote:
> > On Mon, Jan 17, 2022 at 05:57:19PM +0000, Paul Backus via Digitalmars-d wrote:
> > > 
> > > I think the best way to describe the behavior specified by the DIP is that the compiler rewrites
> > > 
> > >     noreturn x;
> > > 
> > > to
> > > 
> > >     noreturn x = void;
> > > 
> > > So, there is a special case here, but it does not require noreturn to have a default constructor.
> > 
> > The question then would be, why such a special case?  There's no need to have a special case here, since aborting/terminating on declaring a variable of type noreturn is perfectly reasonable semantics for a bottom type.
> 
> Both the rewrite I describe and the behavior you propose are special cases.  The non-special-case behavior is "compile-time error."

OK, so it should be a compile-time error, then.


T

-- 
Try to keep an open mind, but not so open your brain falls out. -- theboz
January 17, 2022
On Mon, Jan 17, 2022 at 06:32:19PM +0000, Elronnd via Digitalmars-d wrote:
> On Monday, 17 January 2022 at 18:05:49 UTC, H. S. Teoh wrote:
> > > What happens if you pass in an A*, and A.sizeof>B.sizeof?
> > 
> > This is exactly what happens when you pass a derived class to a function that expects the base class, BTW.
> 
> You can't do pointer arithmetic on class instances.

Sure you can. Just cast it to void* and arithmetic away.


T

-- 
One Word to write them all, One Access to find them, One Excel to count them all, And thus to Windows bind them. -- Mike Champion
January 17, 2022
On 1/17/22 18:53, Elronnd wrote:
> On Monday, 17 January 2022 at 16:11:03 UTC, Timon Gehr wrote:
>> if a type `A*` is a subtype of a type `B*`, then `A.sizeof>=B.sizeof`. `noreturn*` is a subtype of any `T*`. Hence, `noreturn.sizeof` should be at least `size_t.max` or even `∞`.
> 
> I don't think this is right; it must be that A.sizeof==B.sizeof.

Well, that clearly can't be the case, unless you want to claim that `int.sizeof==noreturn.sizeof==long.sizeof`:

```d
void main(){
     noreturn* null_;
     int* ip = null_;
     long* lp = null_;
     class C{ int* foo(){ return null_; } }
     class D:C{ override noreturn* foo(){ return null_; } }
     int* f(int* b){ return b+1; }
     long* g(long* b){ return b+1; }
     f(null_);
     g(null_);
}
```

In any case, to the question "how big is a value that can never be allocated", "∞" is a natural answer, even if you don't buy the derivation over subtyping.

> 
> B* f(B* b) { return b+1; }
> 
> What happens if you pass in an A*, and A.sizeof>B.sizeof? 

Just another reason why pointer arithmetic is unsafe. E.g., see what happens in C++, where class references are explicitly typed as pointers:

```c++
#include <iostream>
using namespace std;
struct B{ int x; };
struct A:B{ int y=123; };
B* f(B* b){ return b+1; }
int main(){ cout<<f(new A)->x<<'\n';  } // "123"
```
January 17, 2022
On Monday, 17 January 2022 at 18:40:55 UTC, H. S. Teoh wrote:
> On Mon, Jan 17, 2022 at 06:11:09PM +0000, Paul Backus via Digitalmars-d wrote:
>> 
>> Both the rewrite I describe and the behavior you propose are special cases.  The non-special-case behavior is "compile-time error."
>
> OK, so it should be a compile-time error, then.

...and then you need special cases in generic code to deal with noreturn. So the question is, what's the cost/benefit of adding a "pragmatic" special case to the language here?

In any case, the DIP has already gone through the full review process and been accepted, so whether we agree with it or not, the decision has already been made.
January 17, 2022
On Mon, Jan 17, 2022 at 07:23:05PM +0000, Paul Backus via Digitalmars-d wrote:
> On Monday, 17 January 2022 at 18:40:55 UTC, H. S. Teoh wrote:
> > On Mon, Jan 17, 2022 at 06:11:09PM +0000, Paul Backus via Digitalmars-d wrote:
> > > 
> > > Both the rewrite I describe and the behavior you propose are special cases.  The non-special-case behavior is "compile-time error."
> > 
> > OK, so it should be a compile-time error, then.
> 
> ...and then you need special cases in generic code to deal with noreturn. So the question is, what's the cost/benefit of adding a "pragmatic" special case to the language here?

What kind of special cases, specifically?  Making variables of type noreturn illegal does not preclude taking parameters of type noreturn. Most current generic code does tests of the form:

	template someTpl(T)
	if (is(typeof((T t) {
			... // tests on t here
		})))
	{ ... }

This wouldn't be affected by the fact that T may be noreturn. If the generic function actually needs to instantiate a variable of type T, then it *should* be a compile error when T is noreturn anyway (because it can't possibly do anything meaningful with such a variable, and the fact that instantiation wasn't prevented means there's a logic error somewhere).


> In any case, the DIP has already gone through the full review process and been accepted, so whether we agree with it or not, the decision has already been made.

Sine when does that mean things are set in stone?


T

-- 
Latin's a dead language, as dead as can be; it killed off all the Romans, and now it's killing me! -- Schoolboy