Re: Subtyping of an enum

2019-04-15 Thread Alex via Digitalmars-d-learn

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.


Re: Subtyping of an enum

2019-04-15 Thread Anton Fediushin via Digitalmars-d-learn

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!


Re: Subtyping of an enum

2019-04-15 Thread Anton Fediushin via Digitalmars-d-learn

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




Re: Subtyping of an enum

2019-04-15 Thread Alex via Digitalmars-d-learn

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)~");");

}



Re: Subtyping of an enum

2019-04-15 Thread Alex via Digitalmars-d-learn

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.








Re: Subtyping of an enum

2019-04-15 Thread diniz via Digitalmars-d-learn

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}


Re: Subtyping of an enum

2019-04-15 Thread Alex via Digitalmars-d-learn

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...


Re: Subtyping of an enum

2019-04-15 Thread Anton Fediushin via Digitalmars-d-learn

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


Re: Subtyping of an enum

2019-04-15 Thread Anton Fediushin via Digitalmars-d-learn

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:

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


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
```





Re: Subtyping of an enum

2019-04-15 Thread XavierAP via Digitalmars-d-learn

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.


Re: Subtyping of an enum

2019-04-15 Thread XavierAP via Digitalmars-d-learn

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).


Re: Subtyping of an enum

2019-04-15 Thread XavierAP via Digitalmars-d-learn

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:


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?


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)




Re: Subtyping of an enum

2019-04-15 Thread Alex via Digitalmars-d-learn

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


Re: Subtyping of an enum

2019-04-15 Thread Anton Fediushin via Digitalmars-d-learn

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:


Hello! I am currently trying to add a custom `toString` method


Several 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.


I already know that but defining enum with strings would break my 
code:

```
assert(Enum.foo < Enum.bar);
```
Would never succeed.



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.




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


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?





Re: Subtyping of an enum

2019-04-15 Thread Anton Fediushin via Digitalmars-d-learn

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:

[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?


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
```




Re: Subtyping of an enum

2019-04-15 Thread XavierAP via Digitalmars-d-learn

On Monday, 15 April 2019 at 08:39:24 UTC, Anton Fediushin wrote:


Hello! I am currently trying to add a custom `toString` method


Several 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


Re: Subtyping of an enum

2019-04-15 Thread Alex via Digitalmars-d-learn

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?