www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Making enum join variadic

reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
How can I make `join` variadic (by filling in njoin) in the 
following code?

import std.stdio: writeln;
import std.traits;

string enumsHelper(S...)(S s)
{
     typeof(return) r;
     foreach (i, e; s)
     {
         if (i >= 1)
             r ~= ", ";
         r ~= e;
     }
     return r;
}

/** Join/Chain/Concatenate/Unite Enums $(D E1), $(D E2), ... into 
$(D E).
     See also: 
http://forum.dlang.org/thread/f9vc6p$1b7k$1 digitalmars.com
*/
template join(string E, E1, E2)
{
     const join = ("enum " ~ E ~ " { " ~
                    enumsHelper(__traits(allMembers, E1)) ~ "," ~
                    enumsHelper(__traits(allMembers, E2)) ~ " }"
         );
}

template njoin(string E, Ei...)
{
     import std.algorithm: map;
     enum string njoin = "enum " ~ E ~ " { " ~ "" ~ " } ";
}

void main(string[] args)
{
     enum E1 { A, B, C }
     enum E2 { E, F, G }
     mixin(join!("E12", E1, E2));
     E12 e12;
     writeln(e12.min, ",", e12.max);
}
May 01 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Nordlöw:

 How can I make `join` variadic (by filling in njoin) in the 
 following code?
When you have a D tuple (not Phobos tuple), and it contains values all of the same type, you can turn it into an array with just: [mytuple] Once you have an array of strings, you can use the normal phobos function to join the strings as you desire. Bye, bearophile
May 01 2014
prev sibling parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 05/02/14 00:24, "Nordlöw" via Digitalmars-d-learn wrote:
 How can I make `join` variadic (by filling in njoin) in the following code?
import std.array, std.range, std.algorithm; import std.stdio; template Njoin(ES...) { mixin({ string r = "enum Njoin { "; foreach (E; ES) r ~= [__traits(allMembers, E), " "].join(","); return r ~ "}"; }()); } void main(string[] args) { enum E1 { A, B, C } enum E2 { E, F, G } alias E12 = Njoin!(E1, E2); E12 e12; writeln(e12.min, ",", e12.max); } artur
May 01 2014
parent reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
 artur
Thx! Here's my final version that compiles and run: import std.stdio: writeln; import traits_ex: isEnum; import std.typetuple: allSatisfy; /** Join/Chain/Concatenate/Unite Enums $(D E1), $(D E2), ... into $(D E). See also: http://forum.dlang.org/thread/f9vc6p$1b7k$1 digitalmars.com */ template join(ES...) if (allSatisfy!(isEnum, ES)) { mixin({ string r = "enum join { "; foreach (E; ES) { import std.range: join; r ~= [__traits(allMembers, E), " "].join(","); } return r ~ "}"; }()); } unittest { enum E1 { a, b, c } enum E2 { e, f, g } enum E3 { h, i, j} alias E1_ = join!(E1); alias E12 = join!(E1, E2); alias E123 = join!(E1, E2, E3); writeln(E123.min, ",", E123.max); } Some final questions: - Is join a good naming for this? Is chain better? - Is it better to be verbose with joinEnums? - What other useful enum algorithms are you missing? - Should this perhaps go into Phobos? If so in what module? std.algorithm, range, traits?
May 02 2014
next sibling parent =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
Its up: https://github.com/nordlow/justd/blob/master/enums.d
May 02 2014
prev sibling parent reply Philippe Sigaud via Digitalmars-d-learn writes:
On Fri, May 2, 2014 at 12:59 PM, "Nordlöw"
<digitalmars-d-learn puremagic.com> wrote:

 Some final questions:

 - Is join a good naming for this? Is chain better?
 - Is it better to be verbose with joinEnums?
I'd be verbose. It's an uncommon operation, bound to surprise a reader a bit.It's better to type a few more letters. I did not try to compile it, but what happens if the enum elements have the same name ? The same min/max/values ? Like this: enum E1 { a, b, c } alias E111 = join!(E1, E1, E1);
 - What other useful enum algorithms are you missing?
 - Should this perhaps go into Phobos? If so in what module? std.algorithm,
range, traits?
I would put it in std.typecons, since it's a type constructor
May 02 2014
parent reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
 I'd be verbose. It's an uncommon operation, bound to surprise a 
 reader
 a bit.It's better to type a few more letters.
See update.
 I did not try to compile it, but what happens if the enum 
 elements
 have the same name ? The same min/max/values ?

 Like this:

 enum E1 { a, b, c }

 alias E111 = join!(E1, E1, E1);
This should give a better error message, than current mixin error. I'll work on that.
 I would put it in std.typecons, since it's a type constructor
Ok. Thx!
May 02 2014
parent reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
On Friday, 2 May 2014 at 12:45:44 UTC, Nordlöw wrote:
 I'd be verbose. It's an uncommon operation, bound to surprise 
 a reader
 a bit.It's better to type a few more letters.
See update.
 I did not try to compile it, but what happens if the enum 
 elements
 have the same name ? The same min/max/values ?

 Like this:

 enum E1 { a, b, c }

 alias E111 = join!(E1, E1, E1);
This should give a better error message, than current mixin error. I'll work on that.
 I would put it in std.typecons, since it's a type constructor
Ok. Thx!
Here's my try at detecting member names collision at compile time: template MemberNamesUnion(E...) if (allSatisfy!(isEnum, E)) { bool[string] allMembers; // used to detect member collisions mixin({ string r = "enum MemberNamesUnion { "; foreach (T; E) { import std.range: join; foreach (member; __traits(allMembers, T)) { static assert (member in allMembers, "Member collision"); allMembers[member] = true; } r ~= [__traits(allMembers, T)].join(",") ~ ","; } return r ~ " }"; }()); } It fails as enums.d(25,46): Error: static variable allMembers cannot be read at compile time enums.d(25,21): while evaluating: static assert("a" in allMembers) Is there a solution to this problem?
May 02 2014
next sibling parent reply "Meta" <jared771 gmail.com> writes:
On Friday, 2 May 2014 at 13:38:39 UTC, Nordlöw wrote:
 enums.d(25,46): Error: static variable allMembers cannot be 
 read at compile time
 enums.d(25,21):        while evaluating: static assert("a" in 
 allMembers)

 Is there a solution to this problem?
Associative arrays are not CTFE-able.
May 02 2014
parent reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
On Friday, 2 May 2014 at 14:36:16 UTC, Meta wrote:
 On Friday, 2 May 2014 at 13:38:39 UTC, Nordlöw wrote:
 enums.d(25,46): Error: static variable allMembers cannot be 
 read at compile time
 enums.d(25,21):        while evaluating: static assert("a" in 
 allMembers)

 Is there a solution to this problem?
Associative arrays are not CTFE-able.
So that leaves me with using an array of bool and rank() then, I guess...
May 02 2014
parent =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
 So that leaves me with using an array of bool and rank() then, 
 I guess...
Correction: I mean array of strings and find.
May 02 2014
prev sibling parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 05/02/14 15:38, "Nordlöw" via Digitalmars-d-learn wrote:
 
 template MemberNamesUnion(E...) if (allSatisfy!(isEnum, E))
 {
     bool[string] allMembers;   // used to detect member collisions
     mixin({
             string r = "enum MemberNamesUnion { ";
             foreach (T; E) {
                 import std.range: join;
                 foreach (member; __traits(allMembers, T)) {
                     static assert (member in allMembers, "Member collision");
                     allMembers[member] = true;
                 }
                 r ~= [__traits(allMembers, T)].join(",") ~ ",";
             }
             return r ~ " }";
         }());
 }
 
 It fails as
 
 enums.d(25,46): Error: static variable allMembers cannot be read at compile
time
 enums.d(25,21):        while evaluating: static assert("a" in allMembers)
 
 Is there a solution to this problem?
Move the AA declaration to inside the lambda, remove the 'static' from the assert, and fix the condition ("member !in allMembers"), then it will work. artur
May 02 2014
parent reply "Meta" <jared771 gmail.com> writes:
On Friday, 2 May 2014 at 15:18:06 UTC, Artur Skawina via 
Digitalmars-d-learn wrote:
 On 05/02/14 15:38, "Nordlöw" via Digitalmars-d-learn wrote:
 
 template MemberNamesUnion(E...) if (allSatisfy!(isEnum, E))
 {
     bool[string] allMembers;   // used to detect member 
 collisions
     mixin({
             string r = "enum MemberNamesUnion { ";
             foreach (T; E) {
                 import std.range: join;
                 foreach (member; __traits(allMembers, T)) {
                     static assert (member in allMembers, 
 "Member collision");
                     allMembers[member] = true;
                 }
                 r ~= [__traits(allMembers, T)].join(",") ~ ",";
             }
             return r ~ " }";
         }());
 }
 
 It fails as
 
 enums.d(25,46): Error: static variable allMembers cannot be 
 read at compile time
 enums.d(25,21):        while evaluating: static assert("a" in 
 allMembers)
 
 Is there a solution to this problem?
Move the AA declaration to inside the lambda, remove the 'static' from the assert, and fix the condition ("member !in allMembers"), then it will work. artur
But that will also move the compile time check to a runtime one.
May 02 2014
parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 05/02/14 17:27, Meta via Digitalmars-d-learn wrote:
 On Friday, 2 May 2014 at 15:18:06 UTC, Artur Skawina via Digitalmars-d-learn
wrote:
 On 05/02/14 15:38, "Nordlöw" via Digitalmars-d-learn wrote:
 template MemberNamesUnion(E...) if (allSatisfy!(isEnum, E))
 {
     bool[string] allMembers;   // used to detect member collisions
     mixin({
             string r = "enum MemberNamesUnion { ";
             foreach (T; E) {
                 import std.range: join;
                 foreach (member; __traits(allMembers, T)) {
                     static assert (member in allMembers, "Member collision");
                     allMembers[member] = true;
                 }
                 r ~= [__traits(allMembers, T)].join(",") ~ ",";
             }
             return r ~ " }";
         }());
 }

 It fails as

 enums.d(25,46): Error: static variable allMembers cannot be read at compile
time
 enums.d(25,21):        while evaluating: static assert("a" in allMembers)

 Is there a solution to this problem?
Move the AA declaration to inside the lambda, remove the 'static' from the assert, and fix the condition ("member !in allMembers"), then it will work.
But that will also move the compile time check to a runtime one.
No; mixin arguments are always evaluated at CT. artur
May 02 2014
parent =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
 artur
Collision detection should now be complete. https://github.com/nordlow/justd/blob/master/enums.d Superb!
May 02 2014