August 01
If you really want conditional enums, you can do this:

```
struct E
{
    enum A = 3;
    enum B = 4;
    version (XYZ) enum C = 5;
}

E e = E.A;
```
August 01
On 7/31/2024 7:06 PM, IchorDev wrote:
> You said that it hurts your head to read code like that. But even if it’s ‘fine’, it would compile faster & take fewer lines

Not perceptibly faster (the lexer is very fast), and fewer lines is not always the best thing.

> if we could put conditional compilation in comma-separated lists, particularly enums and (associative) array literals. I would only need to write one array literal instead of a CTFE lambda with a series of ifs. Notice also that I did not nest those ifs, which is slightly worse for performance, but I had to preserve readability. With a single array literal, I would not have to make these compromises.

I do things like this:

```
/// Map to unsigned version of type
__gshared tym_t[256] tytouns = tytouns_init;
extern (D) private enum tytouns_init =
() {
    tym_t[256] tab;
    foreach (ty; 0 .. TYMAX)
    {
        tym_t tym;
        switch (ty)
        {
            case TYchar:      tym = TYuchar;    break;
            case TYschar:     tym = TYuchar;    break;
            case TYshort:     tym = TYushort;   break;
            case TYushort:    tym = TYushort;   break;

            case TYenum:      tym = TYuint;     break;
            case TYint:       tym = TYuint;     break;

            case TYlong:      tym = TYulong;    break;
            case TYllong:     tym = TYullong;   break;
            case TYcent:      tym = TYucent;    break;

            case TYschar16:   tym = TYuchar16;  break;
            case TYshort8:    tym = TYushort8;  break;
            case TYlong4:     tym = TYulong4;   break;
            case TYllong2:    tym = TYullong2;  break;

            case TYschar32:   tym = TYuchar32;  break;
            case TYshort16:   tym = TYushort16; break;
            case TYlong8:     tym = TYulong8;   break;
            case TYllong4:    tym = TYullong4;  break;

            case TYschar64:   tym = TYuchar64;  break;
            case TYshort32:   tym = TYushort32; break;
            case TYlong16:    tym = TYulong16;  break;
            case TYllong8:    tym = TYullong8;  break;

            default:          tym = ty;         break;
        }
        tab[ty] = tym;
    }
    return tab;
} ();
```
to make complex initializers. Works great!

I don't know the details of your particular solution.
August 01
On 7/31/2024 5:54 PM, IchorDev wrote:
> Yes it feels a bit like a dogma,

All languages have their particular dogmas.

Scott Meyers wrote a popular series of "Effective C++" books which are accepted C++ dogma, for example.

D tries to discourage constructs that have a troublesome history. I know that some of these constructs seem like good ideas, the trouble only appears years later.
August 04

On Thursday, 1 August 2024 at 17:46:37 UTC, Walter Bright wrote:

>

If you really want conditional enums, you can do this:

struct E
{
    enum A = 3;
    enum B = 4;
    version (XYZ) enum C = 5;
}

E e = E.A;
e2.d:8:7: error: cannot implicitly convert expression ‘A’ of type ‘int’ to ‘E’
    8 | E e = E.A;

Also fails to catch other issues:

auto e = E.A | 7;

Compiles, but I would prefer it didn't in this case.

The closest I was able to get to something decent (using version in this example is trivial, so only showing inheritance and flag manipulation) is this example:

struct Typedef(T, T init = T.init, string cookie = "", alias inherit_from = T) {
  private T payload = init;

  this(T init) {
    payload = init;
  }

  this(typeof(this) tdef) {
    this(tdef.payload);
  }

  static if (!is(inherit_from : T)) {
    this(inherit_from tdef) {
      this(tdef.payload);
    }
  }

  auto ref opBinary(string op, this X, B)(auto ref B b) if (op != "in") {
     return Typedef(mixin("payload "~op~" b.payload"));
  }

  //static if (!is(inherit_from : T)) {
    auto ref opBinaryRight(string op, this X)(auto ref inherit_from b) {
      return Typedef(mixin("b.payload " ~ op ~ " payload"));
    }
  //}

  //auto ref opCast(T, this X)() {
  //  return cast(T)payload;
  //}
}

struct MMap {
  alias Flags = Typedef!(ulong, 0, "MMap");

  static const Flags None = 0;

  static const Flags A = 1;
  static const Flags B = 2;
};

struct LinuxMMap {
  alias Flags = Typedef!(ulong, 0, "LinuxMMap", MMap.Flags);

  static foreach (x; __traits(allMembers, MMap)) {
    static if (x != "Flags") {
      mixin("static const LinuxMMap.Flags "~x~" = MMap."~x~";");
    }
  }

  static const Flags C = 4;

version (X86_64) {
  static const Flags D = 30;
  static const Flags E = 34;
} else version (AArch64) {
  static const Flags F = 33;
  static const Flags G = 36;
} else {
  static assert(0);
}

}

auto n(T)(T flags0) {
  LinuxMMap.Flags flags = flags0;
  import std;
  writefln("%s %d", flags, flags.payload);
}

void main() {
  n(MMap.A | MMap.B | LinuxMMap.C);
}

The "inheritance" part can be easily wrapped in a reusable mixin template.

It detects (and rejects) constructs like n(MMap.A | 5), etc.

But still accepts n(5), but this is fixable using some template constraints.

So of course this works, and I knew it even before sending initial , but it is just quite ugly.

I also did check generate assembly code, and it looks good (all inlined, and folded to a constant 7 above), at least using gdc.

August 06
It depends on just what you want an enum for. The example I gave was for a scoped collection of named ints, you're right it doesn't not actually create an enum type.
1 2 3
Next ›   Last »