digitalmars.D.learn - Subtyping of an enum
- Anton Fediushin (45/45) Apr 15 2019 Hello! I am currently trying to add a custom `toString` method to
- Alex (15/60) Apr 15 2019 Isn't this a reason for passing your internals encapsulated, like
- Anton Fediushin (15/25) Apr 15 2019 Enum.internal is private to make it inaccessible from any other
- Alex (36/51) Apr 15 2019 This would:
- Anton Fediushin (9/47) Apr 15 2019 This does work unless I want to use it like this:
- Alex (4/15) Apr 15 2019 So... either you pass the internals of Enum somewhere, or you
- XavierAP (30/33) Apr 15 2019 Several remarks... First of all, strings can be compared
- Anton Fediushin (25/59) Apr 15 2019 I already know that but defining enum with strings would break my
- XavierAP (6/19) Apr 15 2019 Yes (leaving aside whether stuff is private or nested) but you
- Anton Fediushin (3/16) Apr 15 2019 Thank you, I understand now! I think I'd have to stick with UFCS
- XavierAP (7/12) Apr 15 2019 If you have defined `x.toString` as a method, UFCS means of
- XavierAP (5/8) Apr 15 2019 Here I should say packages instead of modules... but the general
- diniz (32/42) Apr 15 2019 I don't understand why you just don't call fun with an Enum (struct) par...
- Anton Fediushin (6/40) Apr 15 2019 `fun(Enum(Enum.foo));` would obviously work but `fun(Enum.foo);`
- Alex (32/77) Apr 15 2019 yes,
- Anton Fediushin (2/85) Apr 15 2019 Thank you, this is the solution I have been looking for!
- Alex (25/119) Apr 15 2019 Yes, it is quite nice. D should simply allow enums to act as
- Alex (10/55) Apr 15 2019 Should have been
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.
Apr 15 2019
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.Isn't this a reason for passing your internals encapsulated, like ´´´ Enum EnumInstance = Enum(Enum.internal.foo); fun(EnumInstance); ´´´ ?If there are other ways of achieving the same *and* keeping code clean and organized, please share. Thank you in advance, Anton.Otherwise, you could alwas define fun as ´´´ void fun(Enum.internal e) {} ´´´ but I assume, you want to avoid especially this. In favor of my first proposition, also speaks the fact, that Enum.foo is somewhat awkward w.r.t. your question, as you treat the internal enum as a static member. Was this intended?
Apr 15 2019
On Monday, 15 April 2019 at 10:00:36 UTC, Alex wrote:On Monday, 15 April 2019 at 08:39:24 UTC, Anton Fediushin wrote: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. Something to make the following code work: ``` Enum a = Enum.foo; Enum b = Enum.bar; assert(a == Enum.foo); assert(a < b); assert(a.toString == "FOO"); assert(b.toString == "BAR"); writeln(a); // FOO writeln(b); // BAR ```[snip]Otherwise, you could alwas define fun as ´´´ void fun(Enum.internal e) {} ´´´ but I assume, you want to avoid especially this. In favor of my first proposition, also speaks the fact, that Enum.foo is somewhat awkward w.r.t. your question, as you treat the internal enum as a static member. Was this intended?
Apr 15 2019
On Monday, 15 April 2019 at 10:15:50 UTC, Anton Fediushin wrote:On Monday, 15 April 2019 at 10:00:36 UTC, Alex wrote: 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. Something to make the following code work: ``` Enum a = Enum.foo; Enum b = Enum.bar; assert(a == Enum.foo); assert(a < b); assert(a.toString == "FOO"); assert(b.toString == "BAR"); writeln(a); // FOO writeln(b); // BAR ```This would: ´´´ struct Enum { private { enum internal { foo, bar } internal m_enum; } this(internal i) { m_enum = i; } alias m_enum this; string toString() { if(m_enum == internal.foo) return "FOO"; else return "BAR"; } } void fun(Enum e) {} void main(){ import std.stdio; fun(Enum.init); Enum a = Enum.foo; Enum b = Enum.bar; assert(a == Enum.foo); assert(a < b); assert(a.toString == "FOO"); assert(b.toString == "BAR"); writeln(a); // FOO writeln(b); // BAR } ´´´ Assuming, that automatic generation of "FOO" from foo was not part of your question :-p
Apr 15 2019
On Monday, 15 April 2019 at 10:45:26 UTC, Alex wrote:On Monday, 15 April 2019 at 10:15:50 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 ```On Monday, 15 April 2019 at 10:00:36 UTC, Alex wrote: [snip]This would: ´´´ struct Enum { private { enum internal { foo, bar } internal m_enum; } this(internal i) { m_enum = i; } alias m_enum this; string toString() { if(m_enum == internal.foo) return "FOO"; else return "BAR"; } } void fun(Enum e) {} void main(){ import std.stdio; fun(Enum.init); Enum a = Enum.foo; Enum b = Enum.bar; assert(a == Enum.foo); assert(a < b); assert(a.toString == "FOO"); assert(b.toString == "BAR"); writeln(a); // FOO writeln(b); // BAR } ´´´ Assuming, that automatic generation of "FOO" from foo was not part of your question :-p
Apr 15 2019
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 saidEnum.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...
Apr 15 2019
On Monday, 15 April 2019 at 08:39:24 UTC, Anton Fediushin wrote:Hello! I am currently trying to add a custom `toString` methodSeveral remarks... First of all, strings can be compared (alphabetically) as well as integers, e.g. assert("foo" > "bar") Perhaps not your use case, but worth noting. You have defined your sub-typing the opposite way that you wanted it to work: every `Enum` is an `internal`, but the other way around an `internal` may not work as an `Enum`. Your `fun` would in principle work if it were defined with an `internal` but passed an `Enum`... Of course you have defined `internal` as nested private so no... But then how did you want anything to work if no one outside Enum knows the super-type? You obviously need to re-think your problem and your design :)Obvious solution is to wrap an enum in a structure and utilize 'alias this' for subtyping like this:Actually the obvious solution (not sure if it otherwise works for you) would be to take advantage of D's Uniform Function Call Syntax [1] and define toString as a global function that can be called as a method: enum Fubar { foo, bar } string toString(Fubar fb) { return "It works."; } void main() { import std.stdio; writeln(Fubar.foo.toString); } _________ [1] https://tour.dlang.org/tour/en/gems/uniform-function-call-syntax-ufcs
Apr 15 2019
On Monday, 15 April 2019 at 10:06:30 UTC, XavierAP wrote:On Monday, 15 April 2019 at 08:39:24 UTC, Anton Fediushin wrote:I already know that but defining enum with strings would break my code: ``` assert(Enum.foo < Enum.bar); ``` Would never succeed.Hello! I am currently trying to add a custom `toString` methodSeveral remarks... First of all, strings can be compared (alphabetically) as well as integers, e.g. assert("foo" > "bar") Perhaps not your use case, but worth noting.You have defined your sub-typing the opposite way that you wanted it to work: every `Enum` is an `internal`, but the other way around an `internal` may not work as an `Enum`. Your `fun` would in principle work if it were defined with an `internal` but passed an `Enum`... Of course you have defined `internal` as nested private so no... But then how did you want anything to work if no one outside Enum knows the super-type?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?You obviously need to re-think your problem and your design :)The problem here is that I want to keep methods that are related to an enum inside of this enum for purely aesthetic and organizational purposes.This is what I am doing now, I was just curious if there was a better solution. These global functions pollute global namespace. I know that I could put them into an own module and 'public import' just my enum because these methods would rarely be used by the other components of my application. If I would want to use them though, I'd have to import that ugly module and never forget to call `writeln(a.toString)` instead of `writeln(a)` or else it'll do not what I wanted. And once more, what I want to achieve is purely about overall code organization. I mean, if structs (data) can have functions (methods) that are performed on them, why an enum (single value) cannot have own methods performed on it?Obvious solution is to wrap an enum in a structure and utilize 'alias this' for subtyping like this:Actually the obvious solution (not sure if it otherwise works for you) would be to take advantage of D's Uniform Function Call Syntax [1] and define toString as a global function that can be called as a method: enum Fubar { foo, bar } string toString(Fubar fb) { return "It works."; } void main() { import std.stdio; writeln(Fubar.foo.toString); } _________ [1] https://tour.dlang.org/tour/en/gems/uniform-function-call-syntax-ufcs
Apr 15 2019
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: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)You have defined your sub-typing the opposite way that you wanted it to work: every `Enum` is an `internal`, but the other way around an `internal` may not work as an `Enum`. Your `fun` would in principle work if it were defined with an `internal` but passed an `Enum`... Of course you have defined `internal` as nested private so no... But then how did you want anything to work if no one outside Enum knows the super-type?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?
Apr 15 2019
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:Thank you, I understand now! I think I'd have to stick with UFCS methodOn Monday, 15 April 2019 at 10:06:30 UTC, XavierAP wrote: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)[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?
Apr 15 2019
On Monday, 15 April 2019 at 10:34:42 UTC, Anton Fediushin wrote:The problem here is that I want to keep methods that are related to an enum inside of this enum for purely aesthetic and organizational purposes. ... These global functions pollute global namespace.If you have defined `x.toString` as a method, UFCS means of course you can also call `toString(x)`... So it's debatable what polluting means. More generally you insist on modules and namespaces to be different concepts, which they are (pointlessly) for C++, but not for D (purposely).
Apr 15 2019
On Monday, 15 April 2019 at 12:38:59 UTC, XavierAP wrote:More generally you insist on modules and namespaces to be different concepts, which they are (pointlessly) for C++, but not for D (purposely).Here I should say packages instead of modules... but the general argument stays. Anyway your design is up to you :) but sub-typing is not reflexive, in D or any language.
Apr 15 2019
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}
Apr 15 2019
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 :`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[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.]
Apr 15 2019
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.
Apr 15 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:Thank you, this is the solution I have been looking for!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.
Apr 15 2019
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: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.On Monday, 15 April 2019 at 08:39:24 UTC, Anton Fediushin wrote:Thank you, this is the solution I have been looking for!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.
Apr 15 2019
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)~");"); }
Apr 15 2019