Subtyping of an enum

Anton Fediushin fediushin.anton at yandex.com
Mon Apr 15 20:36:09 UTC 2019


On Monday, 15 April 2019 at 14:20:57 UTC, Alex wrote:
> On Monday, 15 April 2019 at 08:39:24 UTC, Anton Fediushin wrote:
>> Hello! I am currently trying to add a custom `toString` method 
>> to an enum so that:
>> 1. Enum members would still have numeric values and can be 
>> easily compared (things like `enum a { foo = "FOO", bar = 
>> "BAR”}` won't do, I want `a.foo < a.bar)`)
>> 2. More custom methods can be implemented in the future
>>
>> Obvious solution is to wrap an enum in a structure and utilize 
>> 'alias this' for subtyping like this:
>> ```
>> struct Enum {
>>   private {
>>     enum internal {
>>       foo,
>>       bar
>>     }
>>     internal m_enum;
>>   }
>>   this(internal i) { m_enum = i; }
>>   alias m_enum this;
>>   string toString() {
>>     // custom implementation of toString
>>   }
>> }
>> ```
>>
>> This seems to work just fine for assigning and comparisons but 
>> passing Enum as a function argument does not work:
>> ```
>> void fun(Enum e) {}
>>
>> fun(Enum.foo);
>> ---
>> Error: function fun(Enum e) is not callable using argument 
>> types (internal)
>> Cannot pass argument foo of type internal to parameter Enum e.
>> ```
>>
>> Of course, I could just define a bunch of functions that 
>> accept my enum as the first argument and call them using UFCS 
>> but it'd require to explicitly specify functions instead of D 
>> taking care of that (toString() for structures is called 
>> automagically by functions like writeln) and those functions 
>> would hang around here and there totally unorganized. I prefer 
>> to keep functions inside of structures and classes.
>>
>> If there are other ways of achieving the same *and* keeping 
>> code clean and organized, please share.
>>
>> Thank you in advance,
>> Anton.
>
> yes,
>
> import std.stdio, std.meta, std.traits, std.conv;
>
> enum _MyEnum : int { a,b,c}
>
> struct _Enum(T)
> {
>    T value;
>    alias value this;
>    // generate static field members
>    static foreach(e, v; EnumMembers!T)
>    {
>      pragma(msg, "static MyEnum "~to!string(v)~" = 
> MyEnum(T."~to!string(v)~");");
>      mixin("static MyEnum "~to!string(v)~" = 
> cast(MyEnum)(T."~to!string(v)~");");
>    }
> }
>
> alias _Enum!_MyEnum MyEnum;
>
> void foo(MyEnum e)
> {
>    writeln(to!int(e));
> }
> void main()
> {
>     foo(MyEnum.a);
>     foo(MyEnum.b);
>     foo(MyEnum.c);
> }
>
> https://run.dlang.io/is/WOcLrZ
>
> Note that value is never used, it just makes the cast work and 
> treats the struct as an enum. Not sure if there is a way around 
> that.

Thank you, this is the solution I have been looking for!


More information about the Digitalmars-d-learn mailing list