July 16, 2017
On 16.07.2017 21:49, Guillaume Boucher wrote:
> On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote:
>> It is therefore most natural to say that Bottom.sizeof == ∞.
> 
> True, but size_t.max doesn't have the properties of ∞.
> The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom).
> 

In this case, Bottom.sizeof is a value of type Bottom, which must not exist.
July 16, 2017
On 07/16/2017 04:15 PM, Timon Gehr wrote:
> On 16.07.2017 21:49, Guillaume Boucher wrote:
>> On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote:
>>> It is therefore most natural to say that Bottom.sizeof == ∞.
>>
>> True, but size_t.max doesn't have the properties of ∞.
>> The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom).
>>
> 
> In this case, Bottom.sizeof is a value of type Bottom, which must not exist.

Yah that's not workable. Generally the fewer odd exceptions the better, lest all generic code going forward will have to account for those.

Timon, since you got your first DIP approved, now is the time to keep the momentum going with a new one!


Andrei
July 16, 2017
On 07/13/2017 01:25 PM, Timon Gehr wrote:
> On Wednesday, 12 July 2017 at 14:23:15 UTC, Andrei Alexandrescu wrote:
>> On 07/12/2017 05:32 AM, Timon Gehr wrote:
>>> On 09.07.2017 23:45, Meta wrote:
>>>> ...
>>>> Another case that we should probably just statically disallow:
>>>> ... > This obviously doesn't make any sense anyway
>>>> ... > I don't see a reason for us to ever need to do that
>>> Sorry, but this thinking has no place in type system design. This is precisely how you create a convoluted nonsensical mess.
>>
>> Timon, I think you're very well positioned to author a DIP on this. Getting through acceptance on your static foreach DIP seems to not require a lot of extra work.
>> ...
> 
> I might do that, however there are a couple of open questions (see below).

Sorry missed those... let's see:

> It's perfectly fine to have a type of types which is its own type, especially if you allow non-termination.

<nod>

> I'm saying the D notion of subtyping is a bit messy because memory layout matters and subtyping and implicit conversion are not the same thing. Anyway, my assertion that Bottom cannot be a subtype of all other types was actually incorrect: the compiler does not need to generate code for implicit conversion from Bottom to some other type, so it can be treated as a subtype.

<nod>

> typeof(assert(0))* and typeof(assert(0))[] will hence be subtypes of all other pointer and array types respectively.

Wow. Cool!

> An issue is that we already have typeof(null). typeof(null) and typeof(assert(0))* are two ways to specify almost the same thing. One question is whether typeof(assert(0))* and typeof(null) should be the same, or if the former should not implicitly convert to class references.
> I have also argued in the past that there should be a separate typeof([]). This role would now be filled by typeof(assert(0))[]. However, changing the type of '[]' may break code.

You're on to something here. Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it:

null: a pointer to anything. But can't be dereferenced.
*null: well, therefore... anything. But can't be created.

The latter is a mere consequence of the former.

> I think the DIP should introduce conversion from the start, as conversion is easy to support. It is simple to support in the front end and the code gen for it is literally to emit nothing.

Fantastic. Please kick it off. Thanks!!


Andrei
July 16, 2017
On Sunday, 16 July 2017 at 20:04:25 UTC, Timon Gehr wrote:
> The issue isn't purism, it is type safety. If you create an EvolvedPenguin, upcast it to a Penguin and call the fly method you get UB. So noreturn would indeed need to enforce that all overrides are also noreturn.

I see it as some kind of weak guarantee, where the compiler can assume noreturn only if he knows there are no subtypes involved (e.g. if he's applying devirtualization).

Automatically inheriting the attribute could break existing code (especially if it's inferred).
July 16, 2017
On Sunday, 16 July 2017 at 20:15:11 UTC, Timon Gehr wrote:
> On 16.07.2017 21:49, Guillaume Boucher wrote:
>> On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote:
>>> It is therefore most natural to say that Bottom.sizeof == ∞.
>> 
>> True, but size_t.max doesn't have the properties of ∞.
>> The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom).
>> 
>
> In this case, Bottom.sizeof is a value of type Bottom, which must not exist.

It doesn't exist during runtime, but there's no problem to just generate assert(0) where it's used.

I think my interpretation produces the least exceptions, but if you have a better idea go ahead.

July 17, 2017
On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote:
>> An issue is that we already have typeof(null). typeof(null) and typeof(assert(0))* are two ways to specify almost the same thing. One question is whether typeof(assert(0))* and typeof(null) should be the same, or if the former should not implicitly convert to class references.
>> I have also argued in the past that there should be a separate typeof([]). This role would now be filled by typeof(assert(0))[]. However, changing the type of '[]' may break code.
>
> You're on to something here. Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it:
>
> null: a pointer to anything. But can't be dereferenced.
> *null: well, therefore... anything. But can't be created.
>
> The latter is a mere consequence of the former.

I'd really prefer if you avoided the whole `typeof(assert(0))` thing.

First off, it's way too verbose for a simple concept. In general, code is much more readable when you can read functions as `Type functionName(args)`, rather than template-style `expr(valueof!(thing + otherThing).typeof) functionName(args)`, so I think it would be better not to encourage adding more expressions as return types.

I think the following:

    noreturn_t logThenQuit(string message)

is much more readable and obvious (especially to a beginner) than:

    typeof(*null) logThenQuit(string message)

Of course, you could implement typeof(*null); and also add noreturn_t as an alias; it might be a good compromise; I'd still dislike it because it encourages people to use the verbose hard to understand version.

The second reason I don't like it is that I feel it's just trying to be clever for the sake of cleverness. I don't think we need a language feature that perfectly matches the idea of not returning from a function on a deep, philosophical level; we just need a way to tell the type system "Hey, this function doesn't return!".

I don't think `typeof(*null)`, or `typeof(assert(0))` brings any advantage in term of real life user code, and I don't think it's worth the confused users that would look at code and go "Uh? What is the type of *null?" or "I thought assert was void! What would you get the type of assert()?".
July 17, 2017
On Monday, 17 July 2017 at 15:39:30 UTC, Olivier FAURE wrote:
> On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote:
>>> An issue is that we already have typeof(null). typeof(null) and typeof(assert(0))* are two ways to specify almost the same thing. One question is whether typeof(assert(0))* and typeof(null) should be the same, or if the former should not implicitly convert to class references.
>>> I have also argued in the past that there should be a separate typeof([]). This role would now be filled by typeof(assert(0))[]. However, changing the type of '[]' may break code.
>>
>> You're on to something here. Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it:
>>
>> null: a pointer to anything. But can't be dereferenced.
>> *null: well, therefore... anything. But can't be created.
>>
>> The latter is a mere consequence of the former.
>
> I'd really prefer if you avoided the whole `typeof(assert(0))` thing.
>
> First off, it's way too verbose for a simple concept. In general, code is much more readable when you can read functions as `Type functionName(args)`, rather than template-style `expr(valueof!(thing + otherThing).typeof) functionName(args)`, so I think it would be better not to encourage adding more expressions as return types.
>
> I think the following:
>
>     noreturn_t logThenQuit(string message)
>
> is much more readable and obvious (especially to a beginner) than:
>
>     typeof(*null) logThenQuit(string message)
>
> Of course, you could implement typeof(*null); and also add noreturn_t as an alias; it might be a good compromise; I'd still dislike it because it encourages people to use the verbose hard to understand version.
>
> The second reason I don't like it is that I feel it's just trying to be clever for the sake of cleverness. I don't think we need a language feature that perfectly matches the idea of not returning from a function on a deep, philosophical level; we just need a way to tell the type system "Hey, this function doesn't return!".
>
> I don't think `typeof(*null)`, or `typeof(assert(0))` brings any advantage in term of real life user code, and I don't think it's worth the confused users that would look at code and go "Uh? What is the type of *null?" or "I thought assert was void! What would you get the type of assert()?".

Yes, this!

July 17, 2017
On 7/17/17 11:39 AM, Olivier FAURE wrote:
> I'd really prefer if you avoided the whole `typeof(assert(0))` thing.
> 
> First off, it's way too verbose for a simple concept.

Noted, thanks. I won't debate this much but for now I disagree. The "no return" type has several particular properties that set it aside (e.g. it's impossible to implement as a library, does things no other types do, etc). It's also used rarely. Therefore it stands to reason to consider an attention-seeking notation for it.

The upside of this is we can always add an alias to give the type a name if we so wish. For now I'd want to experiment with using typeof as notation.


Andrei
July 17, 2017
On Mon, Jul 17, 2017 at 02:10:27PM -0400, Andrei Alexandrescu via Digitalmars-d wrote:
> On 7/17/17 11:39 AM, Olivier FAURE wrote:
> > I'd really prefer if you avoided the whole `typeof(assert(0))`
> > thing.
> > 
> > First off, it's way too verbose for a simple concept.
> 
> Noted, thanks. I won't debate this much but for now I disagree. The "no return" type has several particular properties that set it aside (e.g. it's impossible to implement as a library, does things no other types do, etc).  It's also used rarely. Therefore it stands to reason to consider an attention-seeking notation for it.
[...]

IMO, the observations "used rarely" and "attention-seeking notation" are better satisfied by an attribute named @noreturn than some strange, convoluted, arcane invocation like `typeof(assert(0))`.  Because:

(1) "used rarely" means it should be as non-intrusive as possible as far as the language is concerned -- we should not spend a lot of language real estate on something that's rarely used, nor should it be something complicated to implement, and/or introduces tricky corner cases that we're likely to get wrong on first attempt. A @noreturn attribute is non-intrusive -- doesn't interact with anything else in the language, easy to implement -- has no tricky corner cases.

(2) "attention-seeking": an arcane invocation like `typeof(assert(0))` is harder to parse and therefore more likely to invite people to just gloss over it as "incomprehensible gibberish that I'll just ignore unless I have to look further", than catch people's attention.  Whereas an annotation like `@noreturn` is immediately obvious by its very presence, with a name that instantly tells you what it does while it still holds your attention.

I see `typeof(assert(0))` as the same kind of over-engineering of
something trivially solved and relatively unimportant ("rarely used")
that has unfortunately plagued C++ design and led C++ to become the mess
it is today.  It's sad to see D start down the same path...


T

-- 
I see that you JS got Bach.
July 17, 2017
On Monday, 17 July 2017 at 18:54:37 UTC, H. S. Teoh wrote:
> On Mon, Jul 17, 2017 at 02:10:27PM -0400, Andrei Alexandrescu via Digitalmars-d wrote:
>> On 7/17/17 11:39 AM, Olivier FAURE wrote:
>> > I'd really prefer if you avoided the whole `typeof(assert(0))`
>> > thing.
>> > 
>> > First off, it's way too verbose for a simple concept.
>> 
>> Noted, thanks. I won't debate this much but for now I disagree. The "no return" type has several particular properties that set it aside (e.g. it's impossible to implement as a library, does things no other types do, etc).  It's also used rarely. Therefore it stands to reason to consider an attention-seeking notation for it.
> [...]
>
> IMO, the observations "used rarely" and "attention-seeking notation" are better satisfied by an attribute named @noreturn than some strange, convoluted, arcane invocation like `typeof(assert(0))`.  Because:
>
> (1) "used rarely" means it should be as non-intrusive as possible as far as the language is concerned -- we should not spend a lot of language real estate on something that's rarely used, nor should it be something complicated to implement, and/or introduces tricky corner cases that we're likely to get wrong on first attempt. A @noreturn attribute is non-intrusive -- doesn't interact with anything else in the language, easy to implement -- has no tricky corner cases.
>
> (2) "attention-seeking": an arcane invocation like `typeof(assert(0))` is harder to parse and therefore more likely to invite people to just gloss over it as "incomprehensible gibberish that I'll just ignore unless I have to look further", than catch people's attention.  Whereas an annotation like `@noreturn` is immediately obvious by its very presence, with a name that instantly tells you what it does while it still holds your attention.
>
> I see `typeof(assert(0))` as the same kind of over-engineering of
> something trivially solved and relatively unimportant ("rarely used")
> that has unfortunately plagued C++ design and led C++ to become the mess
> it is today.  It's sad to see D start down the same path...
>
>
> T

+1000!
You've said it all!