On 7/1/22 5:23 PM, Walter Bright wrote:
>On 7/1/2022 12:37 PM, Steven Schveighoffer wrote:
>I also have experience using a language (Swift) which has this feature, and it's really really nice, especially when dealing with verbose enums.
I find this puzzling, because in all my years I have never wanted non-scoped enums. C has them, I am not unfamiliar with them. I've also never heard this desire in 20 years of D.
These are not unscoped enums. There is a fundamental disconnect with what I wrote and what you are thinking I wrote. Swift's enums are not actually as loose type-wise as D's. They cannot convert to anything implicitly.
> >Am I misunderstanding something?
For one thing, you'll have to add all the members of all the enums to the symbol lookup.
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.
>What if they collide? Now you have an argument that may be a member of an arbitrary collection of different enums - which one do you pick for matching porpoises? If you say "try them all for a best match", now you've got a combinatorial explosion if there are several such parameters.
It's a combinatorial explosion only if you wrote function overloads for all the possible combinations. Remember, this doesn't (can't) IFTI enum types from #values. It has to be concrete.
>C solves this by not having overloading. But it still has a massive name collision problem, which is why C programmers routinely use the enum identifier as prefix for the member names - essentially a homemade way of scoping them.
C++ solved the problem by adding scoped enums.
C++ scoped enums are more like Swift in that they don't implicitly convert to the base type. That's not what I'm looking for. What I'm looking for is deferring the lookup of enum member names until we know the type.
> >This doesn't scale well.
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
bar(#a); // cannot match int a
> > --- mod2.d:
import mod1;
int a = 5;
void foo()
{
bar(.a); // error;
}
And I also have used `with` statements, which *mostly* works, but I've come across some head-scratching problems when naming conflicts occur.
Naming conflicts are worse with the proposed rules.
No, they aren't. Because enum #values can only match enums.
I wrote this little piece of code to demonstrate a proof of concept feature (based on existing D syntax). It only works for equality, but probably could be extended for other operations. It will not work for the full features I am looking for (i.e. assignment and implicit conversion for function parameters).
But it gives you an idea how you can defer the type checking until it's needed.
struct EnumValComparer
{
struct EVC(string s) {
bool opEquals(T)(T val) if (is(T == enum))
{
static assert(is(typeof(__traits(getMember, T, s))));
return __traits(getMember, T, s) == val;
}
}
@property auto opDispatch(string s)() {
return EVC!s();
}
}
EnumValComparer ev;
enum ReallyReallyLongName
{
one,
two,
three
}
void main()
{
auto x = ReallyReallyLongName.one;
assert(x == ev.one);
}
imagine instead of ev.one
you wrote #one
.
You can imagine that the compiler can figure this stuff out for everything, including arbitrary expressions between enum values, because it already is dealing with AST, and not simply strings.
-Steve