July 20, 2021

On Tuesday, 20 July 2021 at 15:50:49 UTC, russhy wrote:

>

Hello

I all the time wondered why we always have to be so much verbose with enum, when it's not casting to primitives, it is about repeating their long type name, constantly, all the time

After trying some other languages over the past few years, i discovered in zig you can just ommit the enum type name and just use enums this way: .MY_VALUE

I don't know if that's something that could be supported with D, i am not a compiler dude, so i don't have the answer

Adam on discord mentioned using with(ENUM_TYPE) or just an alias, but i think we go ahead and make it simple

I had prepared a DIP [1], not ready at all, but i wanted to initiate some discussion about that feature

So what do you think? yay? nay? why not?

[1] https://github.com/RUSshy/DIPs/blob/patch-2/DIPs/DIP1xxx.md

In the past I liked the idea, so it's a why not for me.

From what I remember of the experiment this was not pleasant to implement. It required an array of enum declaration to be added to the internal Scope class.

July 21, 2021
On Wed, Jul 21, 2021 at 1:56 AM russhy via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> Hello
>
> I all the time wondered why we always have to be so much verbose with enum, when it's not casting to primitives, it is about repeating their long type name, constantly, all the time
>
> After trying some other languages over the past few years, i discovered in zig you can just ommit the enum type name and just use enums this way: .MY_VALUE
>
> I don't know if that's something that could be supported with D, i am not a compiler dude, so i don't have the answer
>
> Adam on discord mentioned using with(ENUM_TYPE) or just an alias, but i think we go ahead and make it simple
>
> I had prepared a DIP [1], not ready at all, but i wanted to initiate some discussion about that feature
>
> So what do you think? yay? nay? why not?
>
>
> [1] https://github.com/RUSshy/DIPs/blob/patch-2/DIPs/DIP1xxx.md

When I work in C/C++ and other similar languages, I find that on
anything beyound a trivial program and particularly in a library
a namespace gets baked into the variable name. When using D I  find
that the verbosity works out to be the same for example SDL_INIT_VIDEO
becomes SDL_INIT.VIDEO
and then I end up with less verbosity in a switch using with as other
people have mentioned.
July 21, 2021

On Tuesday, 20 July 2021 at 15:50:49 UTC, russhy wrote:

>

So what do you think? yay? nay? why not?

[1] https://github.com/RUSshy/DIPs/blob/patch-2/DIPs/DIP1xxx.md

The . syntax is ambiguous because . is the module-scope operator.
There's also the question of what to do with nested enums:

struct Foo
{
    enum Bar { A, B, }

    void func () {
        assert(A == 0); // Should it work ?

        assert(.A == 0); // Or should it be this ?
        // The above currently refers to the `struct A`.
    }
}

struct A {}

The only time I had found enums to be too verbose is in switch statements.
As mentioned previously, switch (value) with (EnumType)helps. I think we should make it the default (essentiallycases should be in a with (typeof(value))` scope), and that would alleviate most of the pain.

July 21, 2021

On Tuesday, 20 July 2021 at 15:50:49 UTC, russhy wrote:

>

Hello

And the default constructor,
Why can't it like C++: T t; That's all.
Many C++ programmers want to have constructors like C++ as T t{...};.

July 20, 2021
On 7/20/2021 8:10 PM, Mathias LANG wrote:
> struct Foo
> {
>      enum Bar { A, B, }
> 
>      void func () {
>          assert(A == 0); // Should it work ?

If you want anonymous enums, use:

    enum { A, B }

>          assert(.A == 0); // Or should it be this ?

Then you'd have no way to access a module scope symbol with the same name.

>          // The above currently refers to the `struct A`.
>      }
> }
> 
> struct A {}
> ```
> 
> The only time I had found enums to be too verbose is in switch statements.
> As mentioned previously, `switch (value) with `(EnumType)` helps.

Yup.

> I think we should make it the default (essentially `case`s should be in a `with (typeof(value))` scope), and that would alleviate most of the pain.

Sorry, I'm not understanding the pain.
July 20, 2021
On 7/20/2021 9:12 AM, H. S. Teoh wrote:
> OTOH, I agree that sometimes D enums become rather verbose. Especially
> in switch statements where you have to repeat their name for every case.
> Fortunately, this is where D's `with` statement comes in helpful:
> 
> 	enum MyEnum { blah, bleh, bluh }
> 	MyEnum val = ...;
> 	final switch (val) {
> 		case MyEnum.blah: ...
> 		case MyEnum.bleh: ...
> 		case MyEnum.bluh: ...
> 	}

In C, qualifying the member name with the tag name is not only not necessary, it is not allowed. Hence, here how C does it:

        enum MyEnum { MyEnum_blah, MyEnum_bleh, MyEnum_bluh };
	enum MyEnum val = ...;
	switch (val) {
		case MyEnum_blah: ...
		case MyEnum_bleh: ...
		case MyEnum_bluh: ...
	}

It's not very attractive. C++ eventually added some more syntax so the members had to be qualified. This is because once the project exceeds a certain level of complexity, qualifying those enum member names becomes desirable.

But if you still want unqualified names, `alias` is the feature:


    enum MyEnum { blah, bleh, bluh }
    alias blah = MyEnum.blah;
    alias bleh = MyEnum.bleh;
    alias bluh = MyEnum.bluh;

`alias` is an all-purpose tool for moving names from one scope to another. Of course, one can probably do a mixin to automate the alias declarations. It should be a fun exercise. Any takers?

(As mentioned by others, `with` does it too, but `with` only affects the scope it specifies.)
July 21, 2021
On Wednesday, 21 July 2021 at 06:39:18 UTC, Walter Bright wrote:
[...]
> But if you still want unqualified names, `alias` is the feature:
>
>
>     enum MyEnum { blah, bleh, bluh }
>     alias blah = MyEnum.blah;
>     alias bleh = MyEnum.bleh;
>     alias bluh = MyEnum.bluh;

>
> `alias` is an all-purpose tool for moving names from one scope to another. Of course, one can probably do a mixin to automate the alias declarations. It should be a fun exercise. Any takers?

mixin({
  auto aliasList = "";
  static foreach(m; __traits(allMembers, MyEnum))
    aliasList ~= "alias "~m~" = MyEnum."~m~";\n"
  return aliasList;
}());


>
> (As mentioned by others, `with` does it too, but `with` only affects the scope it specifies.)


July 21, 2021
On Wednesday, 21 July 2021 at 06:39:18 UTC, Walter Bright wrote:

>
> But if you still want unqualified names, `alias` is the feature:
>
>
>     enum MyEnum { blah, bleh, bluh }
>     alias blah = MyEnum.blah;
>     alias bleh = MyEnum.bleh;
>     alias bluh = MyEnum.bluh;
>
> `alias` is an all-purpose tool for moving names from one scope to another. Of course, one can probably do a mixin to automate the alias declarations. It should be a fun exercise. Any takers?
>
> (As mentioned by others, `with` does it too, but `with` only affects the scope it specifies.)

```d
enum expandEnum(EnumType, string fqnEnumType = EnumType.stringof) = (){
    string expandEnum = "enum {";
    foreach(m;__traits(allMembers, EnumType)) {
        expandEnum ~= m ~ " = " ~ fqnEnumType ~ "." ~ m ~ ",";
    }
    expandEnum  ~= "}";
    return expandEnum;
}();

enum MyEnum { blah, bleh, bluh }
mixin(expandEnum!MyEnum);

auto e = blah;
```
July 21, 2021

On 7/20/21 11:50 AM, russhy wrote:

>

Hello

I all the time wondered why we always have to be so much verbose with enum, when it's not casting to primitives, it is about repeating their long type name, constantly, all the time

After trying some other languages over the past few years, i discovered in zig you can just ommit the enum type name and just use enums this way: .MY_VALUE

I don't know if that's something that could be supported with D, i am not a compiler dude, so i don't have the answer

Adam on discord mentioned using with(ENUM_TYPE) or just an alias, but i think we go ahead and make it simple

I had prepared a DIP [1], not ready at all, but i wanted to initiate some discussion about that feature

So what do you think? yay? nay? why not?

[1] https://github.com/RUSshy/DIPs/blob/patch-2/DIPs/DIP1xxx.md

I enjoy having this type of shortcut in Swift, and wish D had something similar.

To give some perspective, look no further than configuration options of std.algorithm:

arr.sort!("a < b", .unstable); // instead of SwapStrategy.unstable

Clear as the original, and less verbose. In Swift, enums are used extensively, and I don't think they would be if the shortcut syntax wasn't available.

And in general, any function parameter enums are cumbersome to write in D.

However, using .enumMember isn't viable as noted by several people.

If I were to propose something, it would be to have a short substitute for the type. Something like #.typeMember which then uses the expression type to lookup the member. Then you can do things like #.init or any other type properties that return an instance of the type. It wouldn't be a panacea though, since overloading would make this ambiguous. But assignment/initialization would be unambiguous.

Probably not going to fly in D.

-Steve

July 21, 2021

On Tuesday, 20 July 2021 at 16:34:13 UTC, Paul Backus wrote:

>

On Tuesday, 20 July 2021 at 15:50:49 UTC, russhy wrote:

>

So what do you think? yay? nay? why not?

1 https://github.com/RUSshy/DIPs/blob/patch-2/DIPs/DIP1xxx.md

Currently, name lookup in D is done independently from type-checking. This proposal would require name lookup to depend on type checking in order to compile code like the following example:

enum A { x }
enum B { x }

A var = .x;

One could argue that function overloading is a case where name resolution already depends on type checking. In a sense, x (in the above snippet) would be an overloaded name, which can resolved in a given context.

Note that the question of overloading manifest constants was raised when the first-class function DIP was active. If that DIP is revisited, the question would need to be resolved.

>

I don't think adding this kind of complexity to the language semantics is worth it just to save a few characters.

I don't mind keeping D simpler, but I want to point out that the complexity depends on the scope of the feature.

Function calls are likely harder to implement due to overloading, based on the comment here, but target-typed variable initialization and assignment is likely more straightforward.

OTOH, allowing target-typed literals in one place (variable init / assignment) and not in other (function calls) could be regarded as a pointless and artificial design limitation (similar to how struct literals are allowed only for variable initialization).
That could be the reason why C#'s language team decided to allow target-typed new expressions in both contexts with C# 9: