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