Thread overview
Template mixin problem with EnumMembers
Oct 02, 2021
Ferhat Kurtulmuş
Oct 02, 2021
Adam Ruppe
Oct 02, 2021
Ferhat Kurtulmuş
October 02, 2021

The below code works as expected on https://run.dlang.io/, but not on my computer. And I don't know why?

I want to access enum members like Options.OUT_FILE_NAME instead of Options.StringOption.OUT_FILE_NAME.

Please note that the solutions like "alias something = int;" don't work for me. that is not what I need.

In my local computer, pragma(msg, fullname) outputs like:
cast(StringOption)0
cast(StringOption)1
cast(StringOption)2

some error messages I get:
...\options.d-mixin-86(86,11): Error: declaration expected, not )
...\options.d-mixin-86(86,11): Error: no identifier for declarator tion

import std.stdio;

class Options{
    public:

    enum StringOption {
        OUT_FILE_NAME,
        RPT_FILE_NAME,
        MAP_FILE_NAME
    }

    import std.traits: EnumMembers;
    mixin template StrOptAliases()
    {
        static foreach(fullname; [EnumMembers!(StringOption)]){
            mixin("alias " ~ fullname.stringof[13..$] ~ " = " ~ "Options." ~
                                                   fullname.stringof ~ ";\n");
            pragma(msg, fullname);
        }
    }

    mixin StrOptAliases;
}

void main()
{
    int opt = Options.OUT_FILE_NAME;
    writeln(opt);
}
October 02, 2021

On Saturday, 2 October 2021 at 22:07:23 UTC, Ferhat Kurtulmuş wrote:

>

The below code works as expected on https://run.dlang.io/, but not on my computer. And I don't know why?

You used .stringof. That's undefined behavior. Never use stringof. (except for debugging writes)

Now, I'd actually probably do this entirely differently... just using opDispatch.

class Options{
    public:

    enum StringOption {
        OUT_FILE_NAME,
        RPT_FILE_NAME,
        MAP_FILE_NAME
    }

    static template opDispatch(string name) if(__traits(hasMember, StringOption, name)) {
        alias opDispatch = __traits(getMember, StringOption, name);
    }
}

and done. (even that if template constraint isn't really necessary and im usally anti-those too, but here it kinda makes sense. in theory. in practice it makes zero difference, but in theory, if the dmd regression that broke these error messages ever actually gets fixed, this would lead to better error messages this way. but anyway moving on)

That opDispatch just creates the aliases on-demand. You can't reflect over them directly if you wanted to - you'd still have to check enum members of Options.StringOption, which means things like std.conv.to won't pick it up, but it would work in normal use quite beautifully.

If you did want to do the ahead-of-time static foreach way, remember, never use .stringof. Find another way.

and tbh i'd ditch the std.traits thing too, it just complicates things. Use the language feature allMembers directly and it simplifies to this:

    mixin template StrOptAliases()
    {
        static foreach(name; __traits(allMembers, StringOption))
            mixin("alias " ~ name ~ " = " ~ " __traits(getMember, StringOption, name);");
    }

Notice that the ONLY thing outside the quotes to the mixin is the name. Everything else is inside. That's often the solution to follow my "never use stringof" advice - just leave things inside the quotes. String interpolation / concat is actually very rarely needed to build mixins. New declaration names are the main exception. But most everything else can just be referenced directly and it leads to code that is both less buggy and easier to read.

And, of course, it doesn't rely on random underspecified .stringof behavior that the compiler can change randomly in any release which is just the cherry on top.

October 02, 2021

On Saturday, 2 October 2021 at 22:24:56 UTC, Adam Ruppe wrote:

>

On Saturday, 2 October 2021 at 22:07:23 UTC, Ferhat Kurtulmuş wrote:

>

[...]

You used .stringof. That's undefined behavior. Never use stringof. (except for debugging writes)

[...]

Thank you Adam! I should stop using stringof. Even the docs say it, I ve just seen that https://dlang.org/spec/property.html#stringof.

Probably, I will go for your second solution.

I appreciate it.