DIP 1017--Add Bottom Type--Final Review

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Jan 18 00:17:52 UTC 2019


On Fri, Jan 18, 2019 at 12:45:19AM +0100, Johannes Loher via Digitalmars-d wrote:
> Am 18.01.19 um 00:34 schrieb H. S. Teoh:
[...]
> > In any case, coming back to TBottom*, another issue that makes me
> > wary of defining TBottom* == void is the top pointer `void*`.  Since
> > any pointer implicitly converts to `void*`, this means TBottom*
> > implicitly converts to `void*` too, which in turn means `void`
> > should also implicitly convert to `void*`:
> > 
> > 	void procedure(...) { }
> > 
> > 	void* ptr = procedure(...); // valid if TBottom* == Unit == void
> > 
> > I think the problems that such a construct would cause would far
> > outweigh whatever benefits that we may have reaped from introducing
> > Unit and Bottom types!
> 
> You are absolutely correct. I don't think it makes any sense to define
> `void` to be `Tbottom*` if we don't fix the problem with `void*`.
[...]

Well, void* is simply a bad name for Any*, where Any is the top type.
Even if we fix void* by renaming it to Any* (so that `void*` actually
means a pointer to a unit type, whatever we decide that would be), we
still have the problem of the chain of implicit conversions:

	void --> TBottom* --> Any*

so as long as you define void == TBottom*, you have the weirdness:

	void procedure(...) {}
	Any* ptr = procedure();
	// subsequent fun with casting and dereferencing ptr.

This is why I don't think we should define void == TBottom*, even though
both are ostensibly unit types.  Besides, following the same logic, one
would have to conclude typeof(null) == void too (since typeof(null) also
only contains a single value), which leads to other weird situations.


Anyway, you brought up an excellent point that D's types are not
structural types. So perhaps pointers, including TBottom*, aren't as
simple as we thought they were.  Perhaps we could analyze pointers as
having an implicit (and unrepresented) component identifying themselves
as a pointer type, in addition to holding the pointer value itself. If
you will, they're a product type of an atomic isPointer object with the
pointer value to their specified type.  So TBottom* isn't the same as
the real unit type, which conveys no information; it (implicitly)
conveys the information that it is a pointer, so it may be distinguished
from the unit type as being the product of isPointer with Unit, not just
Unit itself.

Then we can still define void as the unit type, and TBottom* would be a
distinct type that always has the (explicit) value null (with an
associated implicit isPointer attribute).  Dereferencing TBottom* would
then be identical to dereferencing null, which should cause a runtime
abort.

(And similarly, empty structs would not be true unit types either, but
product types of their names with the types of their fields. True
product types in the type theoretic sense would have to be anonymous
structs or entities like std.typecons.Tuple.)

Or alternatively, we can think of TBottom* as a *decorated* type
(decorated with isPointer or TBottom as the type of its target) that is
to be distinguished from the (undecorated) true unit type. Similarly
with named empty structs.


T

-- 
Too many people have open minds but closed eyes.


More information about the Digitalmars-d mailing list