April 15, 2019 Re: Subtyping of an enum | ||||
---|---|---|---|---|
| ||||
Posted in reply to XavierAP | On Monday, 15 April 2019 at 12:25:38 UTC, XavierAP wrote:
> On Monday, 15 April 2019 at 10:34:42 UTC, Anton Fediushin wrote:
>> On Monday, 15 April 2019 at 10:06:30 UTC, XavierAP wrote:
>>> [snip]
>>
>> Isn't this how subtyping works for integers and other types? For example, you have subtyped an integer and added some new methods to it?
>
> Yes (leaving aside whether stuff is private or nested) but you are using the types' relationship the other way around. You have:
>
> static assert(is(Enum : internal));
>
> But you are defining and calling fun() as if it were the other way around (internal : Enum)
Thank you, I understand now! I think I'd have to stick with UFCS method
|
April 15, 2019 Re: Subtyping of an enum | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton Fediushin | On Monday, 15 April 2019 at 13:38:33 UTC, Anton Fediushin wrote: > > This does work unless I want to use it like this: > ``` > 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 > ``` This is correct. And you enforced this behavior as you said > Enum.internal is private to make it inaccessible from any other place. All I want is a way to have > an enum that I could extend with my own methods. So... either you pass the internals of Enum somewhere, or you don't... |
April 15, 2019 Re: Subtyping of an enum | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton Fediushin | Le 15/04/2019 à 10:39, Anton Fediushin via Digitalmars-d-learn a écrit : > 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. > ``` I don't understand why you just don't call fun with an Enum (struct) param, since that is how fun is defined. This works by me (see call in main): struct Enum { private { enum internal { foo, bar } internal m_enum; } this (internal i) { m_enum = i; } alias m_enum this; string toString() { switch (this.m_enum) { case internal.foo : return "FOO" ; case internal.bar : return "BAR" ; default : assert(0) ; } } } void fun (Enum e) { writeln(e) ; } void main() { auto e = Enum(Enum.foo) ; fun(e) ; // -> "FOO" } [And I wouldn't make the enum (little e) private, this just risks complicating code, also eg in testing, I would just not export it.] -- diniz {la vita e estranj} |
April 15, 2019 Re: Subtyping of an enum | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton Fediushin | 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. |
April 15, 2019 Re: Subtyping of an enum | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton Fediushin | 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. Should have been struct _Enum(T) { T value; alias value this; static foreach(e, v; EnumMembers!T) mixin("static T "~to!string(v)~" = cast(_Enum)(T."~to!string(v)~");"); } |
April 15, 2019 Re: Subtyping of an enum | ||||
---|---|---|---|---|
| ||||
Posted in reply to diniz | On Monday, 15 April 2019 at 14:11:05 UTC, diniz wrote:
> Le 15/04/2019 à 10:39, Anton Fediushin via Digitalmars-d-learn a écrit :
>> [snip]
>
> I don't understand why you just don't call fun with an Enum (struct) param, since that is how fun is defined. This works by me (see call in main):
>
> struct Enum {
> private {
> enum internal {
> foo,
> bar
> }
> internal m_enum;
> }
> this (internal i) { m_enum = i; }
> alias m_enum this;
> string toString() {
> switch (this.m_enum) {
> case internal.foo : return "FOO" ;
> case internal.bar : return "BAR" ;
> default : assert(0) ;
> }
> }
> }
>
> void fun (Enum e) {
> writeln(e) ;
> }
>
> void main() {
> auto e = Enum(Enum.foo) ;
> fun(e) ; // -> "FOO"
> }
>
> [And I wouldn't make the enum (little e) private, this just risks complicating code, also eg in testing, I would just not export it.]
`fun(Enum(Enum.foo));` would obviously work but `fun(Enum.foo);` would not. `Enum(Enum` is just redundant, I was looking for a solution that would make code cleaner.
I don't see a problem marking internal enum as private because it isn't accessed outside of the struct
|
April 15, 2019 Re: Subtyping of an enum | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | 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!
|
April 15, 2019 Re: Subtyping of an enum | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anton Fediushin | 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. |
Copyright © 1999-2021 by the D Language Foundation