www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - The enum type inference problem is easily solved with identifier types

reply FeepingCreature <feepingcreature gmail.com> writes:
I just saw the ETI rejection over in Announce, and I just wanted 
to note that there's a handy feature in Neat (my lang), that 
would make this very simple.

Neat has Identifier Types. An identifier is an expression of the 
form `:word`. The type of `:word` is `:word`, ie. identifiers do 
double-duty as types and expressions. The only value that can be 
assigned to a variable of type `:word` is `:word`; it is a type 
with a size of 0, like `void`.

Identifier types were mostly introduced to allow disambiguating 
sumtypes: `void sleep((:delay, long seconds | :until, long 
seconds_since_epoch) target)`. But here they give us an 
unexpected upside.

In terms of effort, it would be extremely easy (though I haven't 
done it yet) to say that an identifier can implicitly convert to 
an enum iff the enum contains a member with the same name as the 
identifier.

What are the advantages of this? There is zero need to complexify 
the compiler by defining contexts in which a type can be 
inferred. There is *no impact* on type inference in this feature. 
The type of `:Dog` is perfectly unambiguous: it's `:Dog`. It so 
happens that a value of this type can implicitly convert to `enum 
Animals { Dog, Cat, Pigeon, }`, but this just uses the 
well-established implicit conversion system, and when it fails 
you get a nice readable error.

Now, this is one instance where a rich typesystem hangs together 
in a way that D's relatively sparse typesystem does not. Consider 
the following: `Animal[] animals = [:Dog, :Cat];`. What is the 
type of the array literal? Since we don't know we're assigning to 
`Animal[]`, D would error here because it cannot unify `:Dog` and 
`:Cat`; they're different types. In Neat, because we have 
built-in sumtypes, we can just say the type is `(:Dog | :Cat)[]`, 
and then notice that oh yeah, this can still implicitly convert 
to `Animal[]`: because every member of the sumtype is implicitly 
convertible, the sumtype is implicitly convertible. But even 
without this, identifier types would allow implementing ETI 
without making the overall language design any more complex - 
they add a built-in type, but they don't change the existing 
language semantics at all.

(If we had `opImplicitCast(T)`, we could implement identifier 
types in a library...)
May 12 2023
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
A nice side effect of this solves None value for a sumtype.

```d
sumtype Foo = string | :None;
```

Add a little bit of semantic to make it the default when its present in 
set and we're good to go.

I like it.
May 12 2023
parent Sebastiaan Koppe <mail skoppe.eu> writes:
On Friday, 12 May 2023 at 09:40:23 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 A nice side effect of this solves None value for a sumtype.

 ```d
 sumtype Foo = string | :None;
 ```

 Add a little bit of semantic to make it the default when its 
 present in set and we're good to go.

 I like it.
I guess you can make enums too: ``` sumtype dir = :Left | :Right; ``` :D
May 12 2023