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).

Every type is peculiar. That's essentially the point of having
types. There is not really a reason to invent a peculiarity ordering
and then add additional special casing for types deemed more
peculiar. (I.e., creating different types of types based on an
informal judgment of peculiarity.)
I seem to recall Haskell calls those "kinds".
...

Indeed, but the separation of types and kinds has no point.
See: https://ghc.haskell.org/trac/ghc/wiki/DependentHaskell

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

In D, subtyping is messy anyway, as you cannot have a subtyping
relationship between values with different memory layout. Hence in D,
Bottom would not actually be a subtype of all other types.

It's a point, and it would make the implementation easier, but it would be a departure from theory. Also it makes user code a tad more awkward.

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.

(Also, a language does not have to support subtyping to have an empty type.)

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

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.

Consider:

typeof(assert(0)) abort(const(char)[] message);
...
int fun()
{
   int x;
   ...
return x != 0 ? 1024 / x : abort("Error: calculation went awry.");
}

I guess such expressions can be rewritten into separate statements:

if (x != 0) return 1024 / x;
abort("Error: calculation went awry.");

and then the compiler figures there's no need for a return following the call to abort.
...

This code compiles and runs:

int x;
...
return x != 0 ? 1024 : (delegate int(){ assert(0,"Error: calculation went awry."); })();

Perhaps a solid plan is to start with a DIP that does not introduce conversion and then experiment with the result for a while. What do you think?
...

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.


Reply via email to