January 15, 2022

On 1/15/22 6:02 AM, Tejas wrote:

>

Not to put words in HS's mouth, but I think the reason why simply declaring the noreturn variable should lead to initialisation is because that's how all variable declarations in D behave, unless you disable default initialisation, at which point it's a compiler error to simply declare the variable.

noreturn not default initializing is therefore a special case, which I feel is undesirable

But noreturn consumes no space. Even if it's not the equivalent of = noreturn.init, it's actually initialized just by declaring it.

I feel the odd thing here is the existance of noreturn.init at all. The reason it does exist is quite simple though -- generic code.

-Steve

January 15, 2022

On Saturday, 15 January 2022 at 14:43:14 UTC, Paul Backus wrote:

>

Making initialization of noreturn fail at runtime would require two special cases: first, the special case of noreturn having no values when every other type in D has at least one value;

noreturn is no more special than 0 number or empty set. They are special cases of the right kind. Divide by zero fails at runtime, but removing 0 because of that would be a bad idea.

>

and second, the special case of noreturn's default initializer not evaluating to a noreturn value when every other type's default initializer evaluates to a value of that type.

I think noreturn.init can be viewed as a value of noreturn.

>

There is an argument to be made that we should never have accepted special case #1 in the first place (i.e., that the noreturn DIP should have been rejected). But given that we have, I think it is better to accept the consequences that follow from that decision, strange though they may seem, than to introduce even more special cases to try and paper over them.

I am not convinced that your special case is better than mine. )

January 15, 2022

On Saturday, 15 January 2022 at 16:34:55 UTC, Max Samukha wrote:

> >

and second, the special case of noreturn's default initializer not evaluating to a noreturn value when every other type's default initializer evaluates to a value of that type.

I think noreturn.init can be viewed as a value of noreturn.

It can't. There are no values of type noreturn. The set of all noreturn values is the empty set. That is literally the definition of a bottom type.

January 15, 2022

On Saturday, 15 January 2022 at 16:55:49 UTC, Paul Backus wrote:

>

It can't. There are no values of type noreturn. The set of all noreturn values is the empty set. That is literally the definition of a bottom type.

Right, but if we want to strictly follow the definitions, then we can't declare a variable of the empty type, because the definition of a variable is literally a name associated with a value, so we are back to where we started.

January 15, 2022

On Saturday, 15 January 2022 at 17:57:02 UTC, Max Samukha wrote:

>

On Saturday, 15 January 2022 at 16:55:49 UTC, Paul Backus wrote:

>

It can't. There are no values of type noreturn. The set of all noreturn values is the empty set. That is literally the definition of a bottom type.

Right, but if we want to strictly follow the definitions, then we can't declare a variable of the empty type, because the definition of a variable is literally a name associated with a value, so we are back to where we started.

Technically, a variable is a name associated with a block of memory, which may or may not contain a value. In the case of noreturn, the block of memory has size 0, and there are no possible values it can contain.

So, technically, a noreturn variable is impossible to initialize. But since the compiler knows that the behavior of the program can't possibly depend on the variable's value, it is free to just skip the initialization altogether and leave the variable uninitialized instead.

I guess you could make an argument that you should have to write noreturn x = void; every time you declare a noreturn variable. But even then, it would not be correct for noreturn x; to result in an assert(0) at runtime--it would have to be a compile-time error.

January 16, 2022

On Saturday, 15 January 2022 at 18:35:02 UTC, Paul Backus wrote:

>

Technically, a variable is a name associated with a block of memory, which may or may not contain a value. In the case of noreturn, the block of memory has size 0, and there are no possible values it can contain.

Memory of size 0 contains a single value, which is the value of the unit type, 0-tuple, or whatever. Zero type is different. Timon, I am totally confused, could you clarify?

>

So, technically, a noreturn variable is impossible to initialize. But since the compiler knows that the behavior of the program can't possibly depend on the variable's value, it is free to just skip the initialization altogether and leave the variable uninitialized instead.

Sounds like "alias x = noreturn.init;"

>

I guess you could make an argument that you should have to write noreturn x = void; every time you declare a noreturn variable. But even then, it would not be correct for noreturn x; to result in an assert(0) at runtime--it would have to be a compile-time error.

I think it depends on the definition of local declaration. For statics, it is obviously a compile-time error. For locals, my feeling is it should be a runtime error, but who knows. Timon, help.

January 17, 2022

On Sunday, 16 January 2022 at 22:56:44 UTC, Max Samukha wrote:

>

On Saturday, 15 January 2022 at 18:35:02 UTC, Paul Backus wrote:

>

Technically, a variable is a name associated with a block of memory, which may or may not contain a value. In the case of noreturn, the block of memory has size 0, and there are no possible values it can contain.

Memory of size 0 contains a single value, which is the value of the unit type, 0-tuple, or whatever. Zero type is different. Timon, I am totally confused, could you clarify?

Unit type = size 0, 1 possible value.
Bottom type = size 0, 0 possible values.

The reason there are 0 possible values is because it is the bottom type, not because its size is 0.

> >

So, technically, a noreturn variable is impossible to initialize. But since the compiler knows that the behavior of the program can't possibly depend on the variable's value, it is free to just skip the initialization altogether and leave the variable uninitialized instead.

Sounds like "alias x = noreturn.init;"

You can't alias an expression, so the above is ill-formed.

> >

I guess you could make an argument that you should have to write noreturn x = void; every time you declare a noreturn variable. But even then, it would not be correct for noreturn x; to result in an assert(0) at runtime--it would have to be a compile-time error.

I think it depends on the definition of local declaration. For statics, it is obviously a compile-time error. For locals, my feeling is it should be a runtime error, but who knows. Timon, help.

It would be a compile-time error for essentially the same reason that default-initializing a type with a @disabled default constructor is a compile-time error: you have asked the compiler to do something that it knows, at compile time, is impossible to do.

I think maybe the misconception that is leading you astray here is that you assume that "default-initializing a variable of type T" requires "evaluating the expression T.init". It does not. What default-initializing a variable of type T requires is

  1. Determining the in-memory representation of T's default value.
  2. Arranging for that representation to be placed in the variable's memory at the start of its lifetime.

In the case of noreturn, the in-memory representation is "nothing", because noreturn has no default value (nor any other values), and arranging for that representation to be placed in the appropriate memory is either impossible or a no-op (depending on how you view things), because there is nothing to place and no memory to place it in.

January 16, 2022
On Mon, Jan 17, 2022 at 12:32:37AM +0000, Paul Backus via Digitalmars-d wrote: [...]
> Unit type = size 0, 1 possible value.
> Bottom type = size 0, 0 possible values.
> 
> The reason there are 0 possible values is because it is the bottom type, not because its size is 0.
[...]

> On Sunday, 16 January 2022 at 22:56:44 UTC, Max Samukha wrote:
[...]
> > I think it depends on the definition of local declaration. For statics, it is obviously a compile-time error. For locals, my feeling is it should be a runtime error, but who knows. Timon, help.
> 
> It would be a compile-time error for essentially the same reason that default-initializing a type with a @disabled default constructor is a compile-time error: you have asked the compiler to do something that it knows, at compile time, is impossible to do.

In this case, the bottom type not only has a @disabled default ctor, it *cannot* have any ctors (because it has no values). It can never be constructed.


> I think maybe the misconception that is leading you astray here is that you assume that "default-initializing a variable of type `T`" requires "evaluating the expression `T.init`". It does not. What default-initializing a variable of type `T` requires is
> 
> 1. Determining the in-memory representation of `T`'s default value. 2. Arranging for that representation to be placed in the variable's memory at the start of its lifetime.

IMO this is conflating the implementation of default initialization and the conceptual semantics of declaring a variable at the language level. In my mind, a variable of some type T is box that stores values of type T. A variable declaration without an initializer is simply a box that holds the default value of T.  Since noreturn has no values, it also doesn't have a default value, so such a box cannot exist. A box that holds something that cannot exist is a contradiction; i.e., declaring a variable of type noreturn is a logic error that should either cause a compilation error or abort at runtime.


> In the case of `noreturn`, the in-memory representation is "nothing", because `noreturn` has no default value (nor any other values), and arranging for that representation to be placed in the appropriate memory is either impossible or a no-op (depending on how you view things), because there is nothing to place and no memory to place it in.

The in-memory representation doesn't exist, because noreturn has no values. This is different from something that has a zero-size representation (i.e., a unit type). It's a contradiction to be in a situation where such a representation is needed (regardless of its size), because it can't exist.  So IMO it should be impossible.


T

-- 
Век живи - век учись. А дураком помрёшь.
January 17, 2022
On 16.01.22 23:56, Max Samukha wrote:
> On Saturday, 15 January 2022 at 18:35:02 UTC, Paul Backus wrote:
>>
>> Technically, a variable is a name associated with a block of memory, which may or may not contain a value. In the case of `noreturn`, the block of memory has size 0, and there are no possible values it can contain.
> 
> Memory of size 0 contains a single value, which is the value of the unit type, 0-tuple, or whatever. Zero type is different. Timon, I am totally confused, could you clarify?
> ...

I share your confusion. A block of memory of size zero indeed has a unique value, not zero values. I don't think there is any principled way to arrive at a semantics where the program survives an attempt to initialize a `noreturn` variable. Also, note that typically, 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 `∞`. Thus, `noreturn.sizeof == 0` is already a special case with a pragmatic justification and using it to attempt to justify any further behavior of `noreturn` is questionable in the first place.

>>
>> So, technically, a `noreturn` variable is impossible to initialize. But since the compiler knows that the behavior of the program can't possibly depend on the variable's value, it is free to just skip the initialization altogether and leave the variable uninitialized instead.
> 
> Sounds like "alias x = noreturn.init;"
> 
>>
>> I guess you could make an argument that you should have to write `noreturn x = void;` every time you declare a `noreturn` variable. But even then, it would not be correct for `noreturn x;` to result in an `assert(0)` at runtime--it would have to be a *compile-time* error.
> 
> I think it depends on the definition of local declaration. For statics, it is obviously a compile-time error. For locals, my feeling is it should be a runtime error, but who knows. Timon, help.

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 am not sure whether that's pragmatically the right choice, because it's a special case and generic code might check whether some type is default-constructible and only in this case declare a local variable of that type. At least it crashes at the latest possible moment, I guess. It's certainly a bit weird that now, in D, 0·x is not always 0.
January 17, 2022
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?