DIPX: Enum Literals / Implicit Selector Expression

Timon Gehr timon.gehr at gmx.ch
Tue Jul 5 23:19:19 UTC 2022


On 7/1/22 21:20, Steven Schveighoffer wrote:
> On 7/1/22 2:22 PM, Walter Bright wrote:
>> On 7/1/2022 8:42 AM, Steven Schveighoffer wrote:
>>> 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
>>> ```
>>
>> That's because the initializer, *after* it is evaluated for its type, 
>> gets cast to the type of the lvalue.
> 
> Not really.
> 
> ```d
> auto a = [1, 2, 3];
> short[] b = [1, 2, 3];
> auto c = cast(short[])a;
> writeln(b); // [1, 2, 3]
> writeln(c); // [1, 0, 2, 0, 3, 0]
> ```
> 
> casting the literal is not the same as casting a regular value of that 
> type.
> 
> What I am talking about is a thing that has not yet been given a type, 
> and becomes the type you need if it's a valid use. Just like an array 
> literal -- it's a complex expression that maintains it's polysemous 
> quality. The only difference is, an enum `#value` would not have a 
> default type.
> 
> -Steve

An even better analogy:

```d
void main(){
     auto dg = x=>x; // error
     // ...
}
```

This lambda does not have a default type, but it will infer the 
parameter type if one is provided:

```d
void main(){
     int delegate(int) dg = x=>x; // ok
     // ...
}
```

It can even match two distinct types:

```d
void foo(int delegate(int) dg){}
void foo(float delegate(float) dg){}

void main(){
     foo(x=>x); // error, ambiguous
     // ...
}
```

I.e., in terms of type checking, everything has already been figured out 
and works:

```d
import std;

alias Poly(T)=T delegate(T=T.init);
enum poly(string name)=q{
     (x){
         static if(is(typeof(typeof(x).%s)))
             return typeof(x).%s;
     }
}.format(name,name);

enum Foo{
     a,
     b,
}
enum Bar{
     b,
     c,
}

void foo(Poly!Foo foo){ writeln(foo()); }
void foo(Poly!Bar bar){ writeln(bar()); }

void main(){
     foo(mixin(poly!"a")); // ok, calls first overload
     // foo(mixin(poly!"b")); // error, matches both
     foo(mixin(poly!"c")); // ok, calls third overload
}
```

So it's just a matter of reusing this logic. How reusable it is I don't 
know, but I guess it has been debugged before.

Therefore, I think the main question that remains is syntax, semantics 
is a solved problem. (Or more pessimistically, any bugs in semantics are 
already in the compiler today.)


More information about the Digitalmars-d mailing list