On Monday, 15 April 2019 at 20:36:09 UTC, Anton Fediushin wrote:
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!
Yes, it is quite nice. D should simply allow enums to act as
structs, they are effectively the same.[meaning they should
should allow methods having methods]
You might want to add a little more functionality. I screwed up
the code when generalizing it, here is a bit better version:
https://run.dlang.io/is/yyuy77
Using the struct you can leverage all the power of op's such as
dispatching, assignment, etc.
Essentially one is just using a standard struct but using enum's
to define the names and values(since they are auto filled).
D should just do away with enums and allow one to create a enum
struct, e.g.,
struct S
{
enum : int
{
a,b,c
}
}
Of which enum S : int { a,b,c } is short hand when one does not
want to add new functionality or D could just treat enum like a
struct by allowing methods inside the enum.
The code I created essentially emulates this, one can make the
enum internal and private to hide it.