DIPX: Enum Literals / Implicit Selector Expression

Steven Schveighoffer schveiguy at gmail.com
Fri Jul 1 15:42:20 UTC 2022


On 7/1/22 1:28 AM, Walter Bright wrote:
> On 6/30/2022 8:41 AM, ryuukk_ wrote:
>>      Color color = .orange; <--- it obviously pick orange, it already 
>> expect an enum
> 
> That is top-down type inference. D is designed to be bottom-up type 
> inference. Because of overloading, having both top-down and bottom-up in 
> play would be very confusing and likely a rich source of confusing bugs. 
> People find overloading confusing enough already.

Yes, but this is not exactly a case without precedent e.g.:

```d
short[] x = [1, 2, 3]; // short[]
auto y = [1, 2, 3]; // int[]

void foo(short[] arr);
foo([1, 2, 3]); // works
```

We do have:

```d
auto color = Color.orange;
```

which has no repeats of the Color enum. However, this doesn't scale for 
bitwise enums:

```d
auto mask = Enum.optionA | Enum.optionB;
```

I would love it for function overloading to work, and it's definitely 
not possible for `.value` to be the syntax since that's already taken. 
But *something* along these lines would be very nice.

How I would design it:

1. We designate a syntax for "enum value", which is a polysemous literal 
(akin to how `1` is polysemous for `int`, `short`, `byte`, `bool`, etc.) 
that can be resolved as any `enum` type with that specific member name. 
For purposes of argument, let's say it's `#value`.

2. If you try to assign it to a specific enum, it gets resolved to that 
enum's type. e.g. `Color c = #orange;`

3. If you try to use it as a function parameter, it gets resolved only 
if there is no ambiguity.

```d
enum A { a, b }
enum B { b, c }

void bar(int x);
void foo(A a);
void foo(B b);

foo(#a); // calls foo(A)
foo(#b); // error, ambiguous
bar(#a); // error, must be used as an enum type
```

4. If it gets used as a non enum type, or an unknown type, then it's a 
compiler error.

```d
enum A { a, b }

auto x = #a; // error
int y = #a; // error
void foo(T)(T t) {}
foo(#a); // error
```

5. If a `#value` literal is used in an expression with only other 
`#value` literals that would normally result in the type of an `enum`, 
the compiler will treat the entire expression as a polysemous literal 
for any `enum` with all the given names.

```d
enum A { a, b, c }
enum B { b, c, d }

A x = #a | #b; // ok
auto y = #a | #b; // error, #expression must be used as an enum
A z = #a | #d; // error, d is not a member of A

void foo(A a);
void foo(B b);

foo(#a | #b); // calls foo(A)
foo(#b | #c); // error, ambiguous
```

Why does it work? Because the type is not an enum, it's an enum 
expression without any type until it's used as an enum. Since all the 
values are compile-time, it shouldn't be a problem to generate the 
constant at the time the type is resolved.

Is this possible? If so, would it be allowed? No sense in working on 
something that has no chance of acceptance, even if it is sound.

I will say, this is one thing from Swift that I really miss in D.

-Steve


More information about the Digitalmars-d mailing list