Thread overview
Using Enums to Generate Scoped List of Names
Aug 04
Dennis
21 hours ago
Dennis
14 hours ago
Walter Bright
13 hours ago
Ali Çehreli
10 hours ago
Walter Bright
August 03

I was looking at Walter's "Strawberries and Cream" presentation this morning and "Using Enums to Generate Scoped List of Names" section caught me with bad feeling: why do you need to generate code using string mixins if this can be done in more readable way (IMHO). So I played with it a bit and here is my solution:

    static struct S(E, T)
    {
        private T flags;
        private enum mask(string name) = 1 << __traits(getMember, E, name);

        pure nothrow @nogc @safe final {
            bool opDispatch(string name)(bool v)
            {
                v ? (flags |= mask!name) : (flags &= ~mask!name);
                return v;
            }
            bool opDispatch(string name)() const scope
            {
                return !!(flags & mask!name);
            }
        }
    }

    enum F {square,circle,triangle }

    S!(F, ubyte) s;

    assert(s.square = true);
    assert(!(s.circle = false));
    assert(s.triangle = true);

    assert(s.square);
    assert(!s.circle);
    assert(s.triangle);

Compare with this from the presentation:

    string generateBitFlags(E, T)() {
        string result = "pure nothrow @nogc @safe final {";
        enum enumName = __traits(identifier, E);

        foreach (size_t i, mem; __traits(allMembers, E)) {
            static assert(i < T.sizeof * 8, "too many fields”);
            enum mask = "(1 << "~i.stringof~")";
            result ~= "

            bool "~mem~"() const scope { return !!(flags & "~mask~"); }

            bool "~mem~"(bool v) {
                v ? (flags |= "~mask~") : (flags &= ~"~mask~");
                return v;
            }";
        }
        return result ~ "}\n private "~T.stringof~" flags;\n";
    }

    static struct S
    {
        mixin(generateFlags!(F, ubyte));
    }

    enum F { square, circle, triangle }

    S s;

    s.square = true;
    s.circle = false;
    s.triangle = true;

    assert(s.square == true);
    assert(s.circle == false);
    assert(s.triangle == true);

My solution can even support sparse bitmasks by simply tuning the enum:
enum F {square, circle=5, triangle=7 }

August 04

On Wednesday, 3 August 2022 at 15:49:25 UTC, Andrey Zherikov wrote:

>

why do you need to generate code using string mixins if this can be done in more readable way (IMHO).

In DMD, the generated getters/setters are extern(C++) so LDC and GDC can access them from C++. This doesn't work with opDispatch.

August 04

On Thursday, 4 August 2022 at 14:45:26 UTC, Dennis wrote:

>

In DMD, the generated getters/setters are extern(C++) so LDC and GDC can access them from C++. This doesn't work with opDispatch.

Will this work? It minimizes string mixins usage an has no opDispatch:

    static struct S(E, T)
    {
        private T flags;

        private template Impl(T mask)
        {
            pure nothrow @nogc @safe final
            {
                bool Impl(bool v)
	            {
    	            v ? (flags |= mask) : (flags &= ~mask);
        	        return v;
            	}

                bool Impl() const scope
	            {
    	            return !!(flags & mask);
                }
            }
        }

        static foreach (mem; __traits(allMembers, E))
            mixin("alias "~mem~" = Impl!(1 << E."~mem~");");
    }

    enum F { square,circle=5,triangle=7 }

    S!(F, ubyte) s;

    assert(s.square = true);
    assert(!(s.circle = false));
    assert(s.triangle = true);

    assert(s.square);
    assert(!s.circle);
    assert(s.triangle);
21 hours ago

On Thursday, 4 August 2022 at 23:31:37 UTC, Andrey Zherikov wrote:

>

Will this work? It minimizes string mixins usage an has no opDispatch:

Sorry for the late reply. I don't think it generates the right extern(C++) symbols for DMD, but I like the solution in general. Minimizing string mixins is good.

14 hours ago
On 8/3/2022 8:49 AM, Andrey Zherikov wrote:
> I was looking at Walter's ["Strawberries and Cream" presentation](https://github.com/dlang/dconf.org/blob/master/2022/online/slides/strawberries.pdf) this morning and "Using Enums to Generate Scoped List of Names" section caught me with bad feeling: why do you need to generate code using string mixins if this can be done in more readable way (IMHO). So I played with it a bit and here is my solution:

Haha, this is a nice improvement! Nobody can think of everything, which is why these forums are worth while!
13 hours ago
On 8/16/22 08:07, Walter Bright wrote:

> Haha, this is a nice improvement! Nobody can think of everything, which is why these forums are worth while!

And your array-at-compile-time example can subjectively be better like this:

import std;

void main() {
  pragma(msg, iota(20).map!(n => n * n).array);
}

Ali
10 hours ago
On 8/16/2022 8:34 AM, Ali Çehreli wrote:
> And your array-at-compile-time example can subjectively be better like this:
> 
> import std;
> 
> void main() {
>    pragma(msg, iota(20).map!(n => n * n).array);
> }

True, but my example was a slide-friendly version of a much more complex piece of real life code.