DIPX: Enum Literals / Implicit Selector Expression

Steven Schveighoffer schveiguy at gmail.com
Tue Jul 5 01:15:28 UTC 2022


On 7/4/22 6:34 PM, Walter Bright wrote:
> On 7/1/2022 3:48 PM, Steven Schveighoffer wrote:
>>
>> No, you don't. You only need to resolve the names when you are 
>> checking whether a function call matches, or an assignment/operation 
>> matches.
> 
> Of course, that precludes `typeof(a)`, `a.sizeof`, `a + 3`, function 
> templates, variadic function parameters.

Yes. The point is to avoid having to write `BigLongEnumTypeName`, and 
that's it. If you use it in places where it's not obvious it should be 
`BigLongEnumTypeName`, it fails.

This does mean that in some cases, you just can't use this feature, and 
that would just have to be the way it is.

One drawback of swift pulling out all the stops to infer everything is 
sometimes it can't, and that leads to annoying messages like "took too 
long to figure out, please split up your expression". I don't want that 
outcome at all for D.

> 
> How do you distinguish an instance of an elem with the same name as an 
> element of the enum?

The literal syntax distinguishes it from everything else. My strawman 
was `#value`, but really, any not-already-used syntax will do. `.value` 
is not available, neither is `value`. The prefix `#` means "this is an 
enum member". It can't be confused with anything else, just like you 
can't have symbols named `1`.

I will stress that I'm not attached to `#` at all, it's just an 
easy-to-type symbol that doesn't already have an existing meaning. 
Another one that might work is `$`, because I think it would be 
unambiguous in this context, but also not sure.

>> It's a combinatorial explosion *only if* you wrote function overloads 
>> for all the possible combinations.
> 
> This implies deferring resolving expressions until trying to do 
> matching, and constantly restarting that for each overload.

I don't feel like this is that difficult, but I profess ignorance on how 
it currently works. I imagine you could have an `EnumValueExpression` 
AST node, which contains the list of members that must be valid. Then 
when trying to match, you check the list of members against the enum itself.

>>>> enum A { a, b, c }
>>>> alias a = A.a;
>>>> alias b = A.b;
>>>> alias c = A.c;
>>>>
>>>> void bar(A a) {}
>>>>
>>>> void foo()
>>>> {
>>>>     int a = 5;
>>>>     bar(a); // error;
>>>> }
>>>
>>> Doesn't your proposal have the same error?
>>
>> No
> 
> I understand what you're doing, but confess that makes me uncomfortable.

Understandable. It's not something I really have enough knowledge to 
make you feel more comfortable with it. This is like a guy who "knows a 
little bit about engines" explaining to a mechanic what he wants done to 
his car. I hope someone with more compiler experience can jump in and 
give some more solid evidence that it's sound. Or alternatively explain 
why it's a really bad idea.

>> I wrote this little piece of code to demonstrate a proof of concept 
>> feature (based on existing D syntax).
> 
> It's clever. With that, is a language change justified?

Yes, because I can't hook assignment, construction, function parameter 
conversion, etc. I.e. I can't hook implicit conversion to a target type. 
I can hook any kind of binary operation, because `opBinaryRight` exists, 
but that would leave something that is half clever but fails in a lot of 
cases. Enough to make it more frustrating than is worth it.

However, it does show the same methodology that I am thinking of -- 
defer the type resolution until it's used, just save the name(s).

-Steve


More information about the Digitalmars-d mailing list