January 17, 2019
On 17/01/2019 11:21 PM, H. S. Teoh wrote:
> On Wed, Jan 16, 2019 at 05:45:13PM -0800, Walter Bright via Digitalmars-d wrote:
> [...]
>> My interest in a bottom type comes from wanting a sounder mathematical
>> basis for types in D, but sadly nobody else seems interested, and this
>> DIP is pretty much DOA.
> 
> Actually, I think most of the negative reactions come not from the
> technical problems of the DIP itself, but from the (perceived or
> otherwise) way it was handled, such as how it got to final review stage
> when it clearly needs more work. It may have sparked less outrage had it
> stayed in draft stage until the technical problems were ironed out.

As someone who will be voting no because I do not feel the feedback has been applied in the DIP, this is correct. While I may agree that getting this passed is a good thing, I do not feel the lack of response is.
January 17, 2019
On Thursday, 17 January 2019 at 00:09:50 UTC, H. S. Teoh wrote:
> So you see, `void` is a rats' nest of special cases and ad hoc monkey-patched semantics that's inconsistent with itself.  Sometimes it behaves like a unit type, sometimes it behaves like a bottom type, and sometimes it behaves like a top type, and none of these usages are consistent with each other, nor are they truly consistent with themselves either.

I think `void` can still be saved. I'm not sure about the meaning of "bottom" and "top" types, but I think that with a few non-breaking changes, it can be made to logically be the polar opposite of typeof(assert(0)):

-Where any type would be convertible to `typeof(assert(0))`, no type is convertible to `void`.
-Where no type is convertible from `typeof(assert(0))`, any type could be made convertible from `void`, the only possible value of void converting to target type's `.init` value.
-Where a pointer to `typeof(assert(0))` can point to nothing, a pointer to `void` can point to anything.
-Where `typeof(assert(0))`, being capable of representing any type possible without loss of information, would have infinite size (and thus be impossible), `sizeof(void) == 0`, so it is possible even in systems with no memory at all.
-`void` variables should be valid syntax, that can be assigned (no-op at machine level) and compared (lowered to literal `true` by compiler) to each other.
-Compiler would be free to decide any non-null address for a void variable. Since dereferencing a pointer to void will only result in void, which never uses any memory, it cannot do any harm.

January 17, 2019
On Thu, Jan 17, 2019 at 02:59:09AM +0000, Meta via Digitalmars-d wrote: [...]
> As an aside, the empty enum:
> 
> enum Empty
> {
> }
> 
> Is an uninhabited type similar to Bottom, but is not implicitly convertible to any other type, unlike Bottom.

Unfortunately, you get a compile error for this declaration.

But assuming it were allowed, then it would be possible to declare multiple distinct empty enums that do not interconvert with each other, which would mean that there is not one, but arbitrarily many bottom types of this kind.


> The empty struct:
> 
> struct Unit
> {
> }
> 
> Unit u;
> writeln(u); // Prints Unit()

Oddly enough, Unit.sizeof == 1, as a hack for generating distinct addresses when you declare multiple instances of Unit. One would have expected .sizeof == 0 for a unit type (and NaN or an error if you attempted to take .sizeof of an empty enum, if empty enums were allowed).


T

-- 
It is widely believed that reinventing the wheel is a waste of time; but I disagree: without wheel reinventers, we would be still be stuck with wooden horse-cart wheels.
January 17, 2019
On Thursday, 17 January 2019 at 00:09:50 UTC, H. S. Teoh wrote:
> So you see, `void` is a rats' nest of special cases and ad hoc monkey-patched semantics that's inconsistent with itself.  Sometimes it behaves like a unit type, sometimes it behaves like a bottom type, and sometimes it behaves like a top type, and none of these usages are consistent with each other, nor are they truly consistent with themselves either.  It's like working with a number system that has no concept of zero, negative numbers, or infinity, and then patching in a new number (let's call it X) that sometimes behaves like zero, sometimes like a negative number, and sometimes like infinity.  Good luck doing calculations involving X.

Noob question, but wouldn't a top type also be a unit type?

I'm visualizing a top type as the type of an aggregate with zero member, which makes it a supertype of any other aggregate (whereas a bottom type would be the type of an aggregate with infinite members); wouldn't that type then have only one single value?
January 17, 2019
On Thursday, 17 January 2019 at 10:35:00 UTC, Dukc wrote:
> I think `void` can still be saved. I'm not sure about the meaning of "bottom" and "top" types, but I think that with a few non-breaking changes, it can be made to logically be the polar opposite of typeof(assert(0)):
>
> -Where any type would be convertible to `typeof(assert(0))`, no type is convertible to `void`.

Sounds good.


> -Where no type is convertible from `typeof(assert(0))`, any type could be made convertible from `void`, the only possible value of void converting to target type's `.init` value.

Consider:

  int n = foo();

A refactoring changes foo() from returning int to returning void. Now n is 0, and the type system is not helping me figure out what's wrong.

On a more theoretical level, void's set of possible values contains exactly one value, and that value is not int.init, string.init or myStruct.init - it's void.init.


> -Where a pointer to `typeof(assert(0))` can point to nothing, a pointer to `void` can point to anything.

> -Where `typeof(assert(0))`, being capable of representing any type possible without loss of information, would have infinite size (and thus be impossible), `sizeof(void) == 0`, so it is possible even in systems with no memory at all.

If void.sizeof == 0, then any void[], regardless of element count, would point to a memory region 0 bytes in size. This conflicts with your previous point.

I'm not averse to making void a unit type, but there seems to be some corners your design doesn't consider.

--
  Simen
January 17, 2019
On Thu, Jan 17, 2019 at 12:02:36PM +0000, Olivier FAURE via Digitalmars-d wrote: [...]
> Noob question, but wouldn't a top type also be a unit type?

No! A unit type is one inhabited by a single value. A top type is a type that can represent *every* value.  Very crudely speaking, if types were numbers, then a unit type is 1, a bottom type is 0, and a top type is infinity. Or, to use a set analogy, a unit type corresponds with a singleton set, a bottom type to the empty set (the subtype of every type), and the top type to the universal set (the supertype of every type).


T

-- 
Change is inevitable, except from a vending machine.
January 17, 2019
On Thu, Jan 17, 2019 at 10:35:00AM +0000, Dukc via Digitalmars-d wrote: [...]
> I think `void` can still be saved. I'm not sure about the meaning of "bottom" and "top" types, but I think that with a few non-breaking changes, it can be made to logically be the polar opposite of typeof(assert(0)):
> 
> -Where any type would be convertible to `typeof(assert(0))`, no type
> is convertible to `void`.
> -Where no type is convertible from `typeof(assert(0))`, any type could
> be made convertible from `void`, the only possible value of void
> converting to target type's `.init` value.

I think you got the conversion direction mixed up.  If typeof(assert(0))
is supposed to be the bottom type, then it must implicitly convert to
every other type (as Walter's DIP stipulates), but no other type could
implicitly convert to it.


> -Where a pointer to `typeof(assert(0))` can point to nothing, a
> pointer to `void` can point to anything.

This is inconsistent with void being a unit type.  A pointer to a unit type can only ever point to the unique value of that type, it cannot point to anything else.

This is where changing void to be a unit type will break every code that uses void*.  Basically, void* is a misnomer inherited from C. It really means any*, where 'any' is the universal type (i.e. the top type). But because C has no such concept as a universal type, the void keyword was contextually redefined to mean 'any' when a pointer type is made from it. It's an unfortunate inconsistency analogous to saying that "one" means "one" when it's a return type, but "one" means "infinity" when you make a pointer from it.  It doesn't make sense as a whole, even though contextually we've come to learn to read void* as any* even though void without the * means something else.

Do not confuse a unit type with the top type. They are very different beasts.


> -Where `typeof(assert(0))`, being capable of representing any type
> possible without loss of information, would have infinite size (and
> thus be impossible), `sizeof(void) == 0`, so it is possible even in
> systems with no memory at all.

I think you're confusing the bottom type with the top type here. :-) The bottom type has *no* values; it's the unique type that cannot represent *anything*. There can be no variables of this type, not because its values are too big, but because it has no values at all.

A type that can represent any type is the top type, and it does not require infinite space: std.variant.Variant, for example, can be considered a top type, because it can hold values of any type. It does not require infinite space.


> -`void` variables should be valid syntax, that can be assigned (no-op
> at machine level) and compared (lowered to literal `true` by compiler)
> to each other.
> -Compiler would be free to decide any non-null address for a void
> variable.  Since dereferencing a pointer to void will only result in
> void, which never uses any memory, it cannot do any harm.

Uhm, a random non-null pointer value can do *lots* of harm, because being a systems language, D lets you cast pointers of one type to a pointer of a different type. Casting a pointer to void to a pointer to int, for example, will let you write to a random memory location. Very dangerous.


T

-- 
Democracy: The triumph of popularity over principle. -- C.Bond
January 17, 2019
On Thursday, 17 January 2019 at 12:40:18 UTC, H. S. Teoh wrote:
> No! A unit type is one inhabited by a single value. A top type is a type that can represent *every* value.  Very crudely speaking, if types were numbers, then a unit type is 1, a bottom type is 0, and a top type is infinity. Or, to use a set analogy, a unit type corresponds with a singleton set, a bottom type to the empty set (the subtype of every type), and the top type to the universal set (the supertype of every type).

I think I'm confused.

Actually, I think I have a pretty good question. Let's imagine we implement two types in D, Unit and Top, so that they match their type theory concepts as best as they can.

Given this code:

    int foo(Unit u) {
        ...
    }

    int bar(Top t) {
        ...
    }

what could you do in `bar` that you couldn't do in `foo`?

(I'd appreciate if you could answer with pseudocode examples, to help communication)
January 17, 2019
On Thursday, 17 January 2019 at 03:30:08 UTC, Meta wrote:
> IMO, this tone is uncalled for. Let's all try to be civil and criticize the DIP, not the person.

That is a criticism of the DIP and the way the DIP has been handled.

The progression of this DIP throughout the stages of review, in spite of a lack of due diligence of research and response to criticisms, ignores the opportunity cost of reviewing higher impact and review ready DIPs, like the copy constructor or template constraint DIPs or any other DIP that is _actually ready_ for review.
January 17, 2019
On Tuesday, 15 January 2019 at 08:59:07 UTC, Mike Parker wrote:
> DIP 1017, "Add Bottom Type", is now ready for Final Review. This is the last chance for community feedback before the DIP is handed off to Walter and Andrei for the Formal Assessment. Please read the procedures document for details on what is expected in this review stage:
>
> https://github.com/dlang/DIPs/blob/master/PROCEDURE.md#final-review
>
> The current revision of the DIP for this review is located here:
>
> https://github.com/dlang/DIPs/blob/4716033a8cbc2ee024bfad8942b2ff6b63521f63/DIPs/DIP1017.md
>
> In it you'll find a link to and summary of the previous review round. This round of review will continue until 11:59 pm ET on January 30 unless I call it off before then.
>
> Thanks in advance for your participation.

The DIP says this:

    Any attempt to use the value of a Tbottom expression is an error.

What does this mean? Just before this statement, we see a set of examples of how TBottom can be "used" inside expressions, i.e.

    a || b

So what does that statement mean then?