www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - foreach over string enum

reply Nrgyzer <nrgyzer gmail.com> writes:
Hey guys,

I'm trying to iterate over an enumeration which contains strings like
the this:

enum FileName : string {
file1 = "file1.ext",
file2 = "file2.ext"
}

I already found this article: http://lists.puremagic.com/pipermail/
digitalmars-d/2007-July/021920.html but it's an enum which contains
integers instead of strings, thus I can't use min- or max-property.

Any suggestions -> thanks in advance!
Feb 10 2011
parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
Nrgyzer Wrote:

 Hey guys,
 
 I'm trying to iterate over an enumeration which contains strings like
 the this:
 
 enum FileName : string {
 file1 = "file1.ext",
 file2 = "file2.ext"
 }
 
 I already found this article: http://lists.puremagic.com/pipermail/
 digitalmars-d/2007-July/021920.html but it's an enum which contains
 integers instead of strings, thus I can't use min- or max-property.
 
 Any suggestions -> thanks in advance!
I'll just be leaving this here, if you need more explanation ask, but maybe you'll understand: import std.stdio; enum FileName : string { file1 = "file1.ext", file2 = "file2.ext" } void main(string args[]) { foreach(a; __traits(allMembers, FileName)) writeln(mixin("FileName." ~ a)); }
Feb 10 2011
next sibling parent Nrgyzer <nrgyzer gmail.com> writes:
== Auszug aus Jesse Phillips (jessekphillips+D gmail.com)'s Artikel
 Nrgyzer Wrote:
 Hey guys,

 I'm trying to iterate over an enumeration which contains strings
like
 the this:

 enum FileName : string {
 file1 = "file1.ext",
 file2 = "file2.ext"
 }

 I already found this article: http://lists.puremagic.com/
pipermail/
 digitalmars-d/2007-July/021920.html but it's an enum which
contains
 integers instead of strings, thus I can't use min- or max-
property.
 Any suggestions -> thanks in advance!
I'll just be leaving this here, if you need more explanation ask,
but maybe you'll understand:
 import std.stdio;
 enum FileName : string {
 file1 = "file1.ext",
 file2 = "file2.ext"
 }
 void main(string args[])
 {
     foreach(a; __traits(allMembers, FileName))
         writeln(mixin("FileName." ~ a));
 }
I've already worked with the mixin-statement, but the __trait is new. As I can see in the documentation, it provides some interesting features. Your solution works great, thanks!
Feb 10 2011
prev sibling parent reply spir <denis.spir gmail.com> writes:
On 02/10/2011 08:22 PM, Jesse Phillips wrote:
 Nrgyzer Wrote:

 Hey guys,

 I'm trying to iterate over an enumeration which contains strings like
 the this:

 enum FileName : string {
 file1 = "file1.ext",
 file2 = "file2.ext"
 }

 I already found this article: http://lists.puremagic.com/pipermail/
 digitalmars-d/2007-July/021920.html but it's an enum which contains
 integers instead of strings, thus I can't use min- or max-property.

 Any suggestions ->  thanks in advance!
I'll just be leaving this here, if you need more explanation ask, but maybe you'll understand: import std.stdio; enum FileName : string { file1 = "file1.ext", file2 = "file2.ext" } void main(string args[]) { foreach(a; __traits(allMembers, FileName)) writeln(mixin("FileName." ~ a)); }
Why the mixin? Is it (just) to have the output string computed at compile-time? Denis -- _________________ vita es estrany spir.wikidot.com
Feb 10 2011
parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
spir Wrote:

 On 02/10/2011 08:22 PM, Jesse Phillips wrote:
 enum FileName : string {
 file1 = "file1.ext",
 file2 = "file2.ext"
 }

 void main(string args[])
 {
      foreach(a; __traits(allMembers, FileName))
          writeln(mixin("FileName." ~ a));
 }
Why the mixin? Is it (just) to have the output string computed at compile-time?
The value of 'a' is the enum field name, not its value. The code will ultimately expand to: void main() { writeln(FileName.file1)); writeln(FileName.file2)); } Which in turn will may have its enum contents expanded to the string value. The mixin is required because it is a named enum and 'a' is a string, not an alias: writeln(FileName.a) doesn't work and nor does: writeln(FileName.mixin(a));
Feb 10 2011
parent reply spir <denis.spir gmail.com> writes:
On 02/10/2011 11:32 PM, Jesse Phillips wrote:
 enum FileName : string {
  >  file1 = "file1.ext",
  >  file2 = "file2.ext"
  >  }
  >
  >  void main(string args[])
  >  {
  >        foreach(a; __traits(allMembers, FileName))
  >            writeln(mixin("FileName." ~ a));
  >  }
Why the mixin? Is it (just) to have the output string computed at compile-time?
The value of 'a' is the enum field name, not its value.
Oops! missed this point ;-) Thanks for the explanation, Jesse. This gave me the opportunity to ask about a detail. The following cannot compile because an argument to string mixin must be a (compile-time) constant: unittest { auto i = 1; auto s = "i"; writeln(mixin("i")); // compiler happy up to here --> "1" writeln(mixin(s)); // compiler unhappy --> "Error: argument to mixin // must be a string, not (s)" } But in your example the symbol a does not look like a constant, instead it the loop variable. Do, how does it work? Or is it that the compiler is able to (1) detect that the collection beeing traversed (__traits(allMembers, FileName)) is a compile-time constant (2) unroll the loop so as to rewrite it first as: foreach(a; ["file1", "file2"]) writeln(mixin("FileName." ~ a)); // *** and then as: writeln(FileName.file1); writeln(FileName.file2); But this doesn't work, neither: auto xx=1, yy=2; auto as = ["x","y"]; foreach(a; as) writeln(mixin(a ~ a)); And in fact the line *** is laso not accepted. So, finally, I understand your code, but not how the compiler processes it so as to see it as a mixin with constant argument. Denis -- _________________ vita es estrany spir.wikidot.com
Feb 10 2011
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
I don't have answers to your other questions.

On 02/10/2011 03:25 PM, spir wrote:

 unittest {
 auto i = 1;
 auto s = "i";
It works if you define s as: enum s = "i";
 writeln(mixin("i")); // compiler happy up to here --> "1"
 writeln(mixin(s)); // compiler unhappy --> "Error: argument to mixin
 // must be a string, not (s)"
It now works. Ali
Feb 10 2011
parent spir <denis.spir gmail.com> writes:
On 02/11/2011 01:02 AM, Ali Çehreli wrote:
 I don't have answers to your other questions.

 On 02/10/2011 03:25 PM, spir wrote:

  unittest {
  auto i = 1;
  auto s = "i";
It works if you define s as: enum s = "i";
  writeln(mixin("i")); // compiler happy up to here --> "1"
  writeln(mixin(s)); // compiler unhappy --> "Error: argument to mixin
  // must be a string, not (s)"
It now works. Ali
Thank you, Ali. denis -- _________________ vita es estrany spir.wikidot.com
Feb 10 2011
prev sibling parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
spir Wrote:

 But in your example the symbol a does not look like a constant, instead it the 
 loop variable. Do, how does it work? 
Magic. No really, the best I can tell is that the compiler will try to run the foreach loop at compile-time if there is something in the body that must be evaluated at compile time. The type you are iterating over must be known at compile-time, and just like any such value it is identified by its type and not its contents. So your array literal could in fact be built with a variable, the fact that it is not doesn't matter. I'm not sure if much thought has gone into compile-time-looping, the best way to enforce it is to get a function to run at compile time. I think the rule of "when the body needs evaluated at compile-time" is what's used, but this also means that when you try to iterate something like __traits or tupleof and don't use a compile-time construct in the body, you don't get an error or the loop executed.
Feb 10 2011
next sibling parent spir <denis.spir gmail.com> writes:
On 02/11/2011 05:27 AM, Jesse Phillips wrote:
 spir Wrote:

 But in your example the symbol a does not look like a constant, instead it the
 loop variable. Do, how does it work?
Magic. No really, the best I can tell is that the compiler will try to run the foreach loop at compile-time if there is something in the body that must be evaluated at compile time. The type you are iterating over must be known at compile-time, and just like any such value it is identified by its type and not its contents. So your array literal could in fact be built with a variable, the fact that it is not doesn't matter. I'm not sure if much thought has gone into compile-time-looping, the best way to enforce it is to get a function to run at compile time. I think the rule of "when the body needs evaluated at compile-time" is what's used, but this also means that when you try to iterate something like __traits or tupleof and don't use a compile-time construct in the body, you don't get an error or the loop executed.
Oh yes, I see. This explains why my example using plain constants (predefined values, thus known at compile-time) does not run: there is nothing /forcing/ the compiler (such as a ref to a type), thus the compiler does not even try. Even if would be less complicated, probably, than with __traits. Denis -- _________________ vita es estrany spir.wikidot.com
Feb 11 2011
prev sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Jesse Phillips" <jessekphillips+D gmail.com> wrote in message 
news:ij2drt$1mq3$1 digitalmars.com...
 Magic.

 No really, the best I can tell is that the compiler will try to run the 
 foreach loop at compile-time if there is something in the body that must 
 be evaluated at compile time.
Actually this happens because __traits(allMembers ...) returns a TypeTuple of string literals. TypeTuples can contain elements of different types (and types themselves as elements), so in order for them to be used in foreach loops, they MUST be unrolled. It's not something in the body, it's the iterable itself that forces unrolling. http://www.digitalmars.com/d/2.0/tuple.html You can do LOTS of cool stuff with this: switch(x) { foreach(i; TypeTuple!(1, 2, 6, 8, 17)) case i: doSomething(); } --------------- class C {} class D : C {} class E : C {} class F : C {} class G : C {} C[] list; foreach(T; TypeTuple!(D, E, F, G)) list ~= new T(); ---------------- int id = runtimeInput(); foreach(i, T; TypeTuple!(C, D ,E, F, G, H)) if (i == id) return new T();
Feb 20 2011