July 09, 2017
On Sunday, 9 July 2017 at 22:28:50 UTC, Andrei Alexandrescu wrote:
> On 07/09/2017 03:12 PM, Walter Bright wrote:
>> On 7/9/2017 6:13 AM, Andrei Alexandrescu wrote:
>>> We should use typeof(assert(0)) for Bottom. There is precedent - there is no name for typeof(null).
>> I had forgotten about the typeof(null) thing. You're right. But there are some issues. What do we do with:
>> 
>>      typeof(assert(0))* p;
>> 
>> ? What does that mean?
>
> That would be a pointer that may only be null - a consequence of the typeof(assert(0)) being uninstantiable.
>
> Generally I'm not too worried about constructs like typeof(assert(0))[], typeof(assert(0))*, use in templates etc - we don't need to "design" these cases, their behavior flows from the properties of typeof(assert(0)) itself.
>
> Similarly, I don't recall ever there being a problem with typeof(null)*, typeof(null)[], people complaining they passed typeof(null) to a template where it did bad things, etc.
>
>
> Andrei

`typeof(null)` actually has one valid value and doesn't crash the program when when you try to create an instance of it. We should not treat this the same as `typeof(null)`.
July 09, 2017
On 07/09/2017 07:34 PM, Meta wrote:
> On Sunday, 9 July 2017 at 22:28:50 UTC, Andrei Alexandrescu wrote:
>> On 07/09/2017 03:12 PM, Walter Bright wrote:
>>> On 7/9/2017 6:13 AM, Andrei Alexandrescu wrote:
>>>> We should use typeof(assert(0)) for Bottom. There is precedent - there is no name for typeof(null).
>>> I had forgotten about the typeof(null) thing. You're right. But there are some issues. What do we do with:
>>>
>>>      typeof(assert(0))* p;
>>>
>>> ? What does that mean?
>>
>> That would be a pointer that may only be null - a consequence of the typeof(assert(0)) being uninstantiable.
>>
>> Generally I'm not too worried about constructs like typeof(assert(0))[], typeof(assert(0))*, use in templates etc - we don't need to "design" these cases, their behavior flows from the properties of typeof(assert(0)) itself.
>>
>> Similarly, I don't recall ever there being a problem with typeof(null)*, typeof(null)[], people complaining they passed typeof(null) to a template where it did bad things, etc.
>>
>>
>> Andrei
> 
> `typeof(null)` actually has one valid value and doesn't crash the program when when you try to create an instance of it. We should not treat this the same as `typeof(null)`.

Agreed (with the mention it's not in contradiction with the above). -- Andrei
July 09, 2017
Let's call the bottom type 'B' for the moment, for convenience.

If we think of it like a floating point NaN, then any type construction of B yields a B:

    const(B) -> B
    B* -> B
    B[] -> B
    X[B] -> B
    B[X] -> B

Since B cannot have a value, any expression that forms a B can be replaced with an assert(0).

    B foo(); // declaration
    foo() -> foo(); assert(0);

    cast(B)exp -> exp; assert(0);

    B b; -> assert(0);

Given a tuple of types:

    alias T = tuple(B,X);

is T equivalent to which of:

    B           (1)
    tuple(X)    (2)
    tuple(Y,X)  (3)
    tuple(B,X)  (4)

? I'm leaning toward (4) as making the most sense.

    struct S {
       T t;
    }

should then yield an error, while:

    struct S {
       T[1..1] t; // t is of type X
    }

would not.
July 09, 2017
On 07/09/2017 05:14 PM, H. S. Teoh via Digitalmars-d wrote:
> On Sun, Jul 09, 2017 at 02:01:08PM -0400, Andrei Alexandrescu via Digitalmars-d 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 like out{ assert(0); } for pretty much the same reasons as Steven
> lists. The biggest pro is that **the language already supports it*.
> Contract syntax already is meant to signal intent, and assert(0) signals
> "never gets here". You can't find a better solution than this. All the
> other alternatives require adding even more baggage to an already
> heavy language, or compiler voodoo to recognize a particular pattern of
> defining a type.  I'd say out{assert(0);} is the principled solution --
> expressing something the current language can already express, and it's
> the other alternatives that are "exotic".
> 

Prioritizing "path of least resistense" over "this is cleaner and more principled" is the hallmark of C++-style langauge design. Please, please, please, let's stay away from that path.
July 10, 2017
On Monday, 10 July 2017 at 03:25:26 UTC, Nick Sabalausky (Abscissa) wrote:
> On 07/09/2017 05:14 PM, H. S. Teoh via Digitalmars-d wrote:
>> On Sun, Jul 09, 2017 at 02:01:08PM -0400, Andrei Alexandrescu via Digitalmars-d 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 like out{ assert(0); } for pretty much the same reasons as Steven
>> lists. The biggest pro is that **the language already supports it*.
>> Contract syntax already is meant to signal intent, and assert(0) signals
>> "never gets here". You can't find a better solution than this. All the
>> other alternatives require adding even more baggage to an already
>> heavy language, or compiler voodoo to recognize a particular pattern of
>> defining a type.  I'd say out{assert(0);} is the principled solution --
>> expressing something the current language can already express, and it's
>> the other alternatives that are "exotic".
>> 
>
> Prioritizing "path of least resistense" over "this is cleaner and more principled" is the hallmark of C++-style langauge design. Please, please, please, let's stay away from that path.

While I agree with your sentiment in principle (heh), we need to keep in mind it purpose.
So far I count four requirements of a solution:
    documentation
    optimisation
    ability to statically reflect upon
    ability to implement

Of the approached listed only out{assert(0);} fails the static reflection check.
Which leaves
1)@noreturn
2)@disable(return)
3)none

1 & 2 are almost functionally identical in their implementation with 2 requiring some semantic hacks to the compiler and precludes the AliasSeq approach below, so I consider 1 to be superior to 2.

this leaves 1 & 3.

w.r.t documentation for 1 this is a solved problem, it becomes part of the type signature and will be picked up in the documentation building tools. 3 it becomes part of the return type and can also be solved by documenting the type.

w.r.t optimisation assuming both 1 & 3  impact DMD equally then there is no difference except that:

Implementation: 3 would require GDC and LDC to make changes _when they already have a solution_. It would also be _considerably more work_ than 1, and would be _backwards incompatible_ with older compilers. In fact 1 could be implemented _Immediately_ for GDC and LDC by having

enum __noreturn;
version (DigitalMars) alias noreturn = __noreturn;
else version(GNU) {
    import gcc.attributes : attribute;
    alias noreturn = AliasSeq!(__noreturn,attribute("noreturn"));
}
else version (LDC)
{
    import ldc.attributes : llvmAttr;
    alias noreturn = AliasSeq!(__noreturn,llvmAttr("noreturn"));
}

and reflect upon the presence of __noreturn;

I am strongly against the need to complicate the compiler when an equal (IMHO better) solution _already exists_, for extremely marginal gain: anyone seriously concerned about the small optimisation benefit will already be using GDC or LDC, the applicability of noreturn is minuscule, AFAICT C's _exit and an unconditional throw (Exception or Error) are the only functions for which it applies.
July 10, 2017
On Sunday, 9 July 2017 at 19:14:37 UTC, Walter Bright wrote:
> On 7/9/2017 6:13 AM, Andrei Alexandrescu wrote:
>> We should use typeof(assert(0)) for Bottom.
>
> That also leaves the door open for:
>
>     alias noreturn = typeof(assert(0));

I would really prefer noreturn (or noreturn_t) to be the default appellation for such a type. typeof(assert(0)) is way uglier, while noreturn is a lot more intuitive and explicit.
July 10, 2017
On 7/10/17 12:02 AM, Nicholas Wilson wrote:
> So far I count four requirements of a solution:
>      documentation
>      optimisation
>      ability to statically reflect upon
>      ability to implement
> 
> Of the approached listed only out{assert(0);} fails the static reflection check.

I'm pretty much giving up on arguing in this thread, as it seems people are really keen to add more bloat to the language in spite of the obvious bloat-free solution.

But I have to ask, what is the benefit of statically determining that a function is noreturn? I thought it was just a hint to the compiler that some optimizations can be done for that call?

-Steve
July 10, 2017
On 2017-07-09 23:14, H. S. Teoh via Digitalmars-d wrote:

> I like out{ assert(0); } for pretty much the same reasons as Steven
> lists. The biggest pro is that **the language already supports it*.
> Contract syntax already is meant to signal intent, and assert(0) signals
> "never gets here". You can't find a better solution than this. 

I highly doubt that the compiler does not need to be changed at all to get the wanted behavior.

It that case it's just as easy to add a compiler recognized UDA. It doesn't add any more baggage than "out{ assert(0); }".

With that said, I don't care that much at all and I'm questioning how useful this feature is to have at all.

-- 
/Jacob Carlborg
July 10, 2017
On Monday, 10 July 2017 at 00:34:54 UTC, Andrei Alexandrescu wrote:
>> `typeof(null)` actually has one valid value and doesn't crash the program when when you try to create an instance of it. We should not treat this the same as `typeof(null)`.
>
> Agreed (with the mention it's not in contradiction with the above). -- Andrei

That was in response to:

>>> Similarly, I don't recall ever there being a problem with typeof(null)*, typeof(null)[], people complaining they passed typeof(null) to a template where it did bad things, etc.

My point was that I don't agree with the analogy as there really isn't any similarity between typeof(assert(0)) and typeof(null). There are no problems with stuff like typeof(null)* etc. because for the most part it's just a regular type, unlike Bottom. Although now that you mention it, there might be some interesting uses for a pointer/array that we statically know can only be null (none that I can think of OTOH though).

I still think we should err on the side of disabling stuff like `immutable Bottom`, `Bottom*`, `Nullable!Bottom`, etc. until we fully understand the ramifications. We also cannot allow struct/class members of the type Bottom for obvious reasons. Interestingly enough, unions would conceptually be okay, and you would statically know that a union such as `union IntOrBottom { int n; Bottom b; }` can only ever contain an int. Therefore, IntOrBottom could safely be aliased away to just int (syntactic differences between working with a union vs. working with an int aside).

We also need to disallow `enum Sneaky: Bottom { val }` and `enum: Bottom { val }`. I don't know how enums are implemented in the compiler so it may be a non-issue. `enum Okay: Bottom {}` is fine and Okay could just alias itself away (but we should still disable it to prevent confusion). `enum: Bottom {}` makes no sense so we should prevent that as well.
July 10, 2017
On Mon, Jul 10, 2017 at 03:47:35PM +0200, Jacob Carlborg via Digitalmars-d wrote:
> On 2017-07-09 23:14, H. S. Teoh via Digitalmars-d wrote:
> 
> > I like out{ assert(0); } for pretty much the same reasons as Steven lists. The biggest pro is that **the language already supports it*. Contract syntax already is meant to signal intent, and assert(0) signals "never gets here". You can't find a better solution than this.
> 
> I highly doubt that the compiler does not need to be changed at all to get the wanted behavior.

I did not say the compiler does not need to be changed. I said the *language* does not need to be changed.


> It that case it's just as easy to add a compiler recognized UDA. It doesn't add any more baggage than "out{ assert(0); }".
> 
> With that said, I don't care that much at all and I'm questioning how useful this feature is to have at all.
[...]

As is usual around here, things of marginal consequence receive the most attention and energy spent in debating every last nitpick. Sigh.


T

-- 
Unix was not designed to stop people from doing stupid things, because that would also stop them from doing clever things. -- Doug Gwyn