digitalmars.D.learn - Mixin programming foreach
- eXodiquas (68/68) Sep 27 2021 Howdy ho everyone,
- Dga123 (25/37) Sep 27 2021 make a `string cps(){}` function. TemplateDeclaration can only
- eXodiquas (11/51) Sep 27 2021 I see, thank you very much for the quick answer.
- Dga123 (17/20) Sep 27 2021 Here's another approach allowing to have a more obvious
- =?UTF-8?Q?Ali_=c3=87ehreli?= (148/208) Sep 27 2021 Often repeated but there are no stupid questions.
- Tejas (8/14) Sep 27 2021 Sometimes I wonder if I should bother writing answers since one
- =?UTF-8?Q?Ali_=c3=87ehreli?= (11/29) Sep 27 2021 I noticed that too. ;) I could have changed other things there as well.=...
- Tejas (6/42) Sep 27 2021 I was also already afraid of post length so I didn't write
- eXodiquas (20/21) Sep 27 2021 Woah, thanks everyone for the ridiculous precise and helpful
- Tejas (65/134) Sep 27 2021 You are trying to write arbitrary statements inside a template,
Howdy ho everyone, I found this forum very helpful for my (maybe) stupid questions, so I give it a try again because I don't understand what's happening here. First of all, I'm not exactly sure what this code here, from the documentation at https://dlang.org/articles/mixin.html, does: ```d template GenStruct(string Name, string M1) { const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct!("Foo", "bar")); ``` In my understanding we create a template called `GenStruct` with compile time arguments `Name` and `M1`. We then create the `char[] GenStruct` which holds the source code for the `struct`. Afterwards we do the `mixin`call and create the source code during compile time to have it ready to go. But I don't understand why the `char[] GenStruct` is there. Is this the name of the `mixin` or is the `template GenStruct` the name of what we pass to the `mixin`? Can we create more than one const char[] in one `template` scope and what would it do if we could? So I'm a bit confused here. But nevertheless, I copied the code and changed it a bit to something like this: ```d template Vector(int dimension) { string cps = ""; foreach(d; 0..dimension) { cps ~= "x" ~ d ~ " = 0;\n"; } const char[] Vector = "struct Vector {\n" ~ dimension.to!string ~ cps ~ "}"; } ``` In my head a call to `mixin(Vector!5)` should result in something like this: ```d struct Vector5 { int x0; int x1; int x2; int x3; int x4; } ``` But it does not compile because `Error: declaration expected, not foreach` which I understand as "foreach is not possible during compile time", whereas I don't see any problem with compile time availability of anything in this template. Obviously I don't understand something here, so it would be awesome if someone could help me out here. :P And as a final question. Let's say the above problems are all solved and I construct such a template. How could I build functions that take any of those `Vector`s as an argument? For example I want to add two of those, the function would look something like this, or am I lost again? ```d Vector!T add(Vector!T lhs, Vector!T rhs) { return ?; } ``` How could I iterate over all components if such a `Vector`? I hope I am not on the completely wrong track to tackle this problem. Thanks in advance. :) eXodiquas
Sep 27 2021
On Monday, 27 September 2021 at 16:23:50 UTC, eXodiquas wrote:Howdy ho everyone, I found this forum very helpful for my (maybe) stupid questions, so I give it a try again because I don't understand what's happening here. [...] But nevertheless, I copied the code and changed it a bit to something like this: ```d template Vector(int dimension) { string cps = ""; foreach(d; 0..dimension) { cps ~= "x" ~ d ~ " = 0;\n";make a `string cps(){}` function. TemplateDeclaration can only contains DeclDefs, i.e declarations and no expressions. b.t.w `template Vector` can also be a string `Vector(int dimension){}` function. So finally to obtain something like this ```d import std; string vector(int dimension) { string cps; foreach(d; 0..dimension) { cps ~= "int x" ~ d.to!string ~ " = 0;\n"; } return "struct Vector" ~ dimension.to!string ~" {\n" ~ cps ~ "}"; } mixin(vector(5)); ``` function used in mixin are evaluated at compile time and are generally more perfomantly evaluated than eponymous template (that contains a single member named as the template). Also less constraint on what can be done. Have a great day, Dga.
Sep 27 2021
On Monday, 27 September 2021 at 16:49:15 UTC, Dga123 wrote:On Monday, 27 September 2021 at 16:23:50 UTC, eXodiquas wrote:I see, thank you very much for the quick answer. So the "macro magic" does not happen in `template`, it happens in the `mixin` call, now I understand. But my last question still stands, how do I build functions that can work with those vectors because the type of those vectors is created at compile time. But I can start working on the problem now. Thanks again for helping me out here. :) Have a great day aswell, eXodiquasHowdy ho everyone, I found this forum very helpful for my (maybe) stupid questions, so I give it a try again because I don't understand what's happening here. [...] But nevertheless, I copied the code and changed it a bit to something like this: ```d template Vector(int dimension) { string cps = ""; foreach(d; 0..dimension) { cps ~= "x" ~ d ~ " = 0;\n";make a `string cps(){}` function. TemplateDeclaration can only contains DeclDefs, i.e declarations and no expressions. b.t.w `template Vector` can also be a string `Vector(int dimension){}` function. So finally to obtain something like this ```d import std; string vector(int dimension) { string cps; foreach(d; 0..dimension) { cps ~= "int x" ~ d.to!string ~ " = 0;\n"; } return "struct Vector" ~ dimension.to!string ~" {\n" ~ cps ~ "}"; } mixin(vector(5)); ``` function used in mixin are evaluated at compile time and are generally more perfomantly evaluated than eponymous template (that contains a single member named as the template). Also less constraint on what can be done. Have a great day, Dga.
Sep 27 2021
On Monday, 27 September 2021 at 16:59:16 UTC, eXodiquas wrote:But my last question still stands, how do I build functions that can work with those vectors because the type of those vectors is created at compile time.Here's another approach allowing to have a more obvious declaration name: ```d import std; string vectorBody(int dimension) { string result; foreach(d; 0..dimension) result ~= "int x" ~ d.to!string ~ " = 0;\n"; return result; } struct Vector(int dimension) { mixin(vectorBody(dimension)); } alias Vector5 = Vector!5; ```
Sep 27 2021
On 9/27/21 9:23 AM, eXodiquas wrote:I found this forum very helpfulSame here. :)for my (maybe) stupid questionsOften repeated but there are no stupid questions.First of all, I'm not exactly sure what this code here, from the documentation at https://dlang.org/articles/mixin.html, does: ```d template GenStruct(string Name, string M1) { const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct!("Foo", "bar")); ``` In my understanding we create a template called `GenStruct` with compile time arguments `Name` and `M1`. We then create the `char[] GenStruct` which holds the source code for the `struct`. Afterwards we do the `mixin`call and create the source code during compile time to have it ready to go.All correct.But I don't understand why the `char[] GenStruct` is there.That example is cofusing because it includes elements that has nothing to do with a string mixin. The following could be used without raising your question: string GenStruct(string Name, string M1) { return "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } unittest { mixin(GenStruct("Foo", "bar")); auto foo = Foo(42); assert(foo.bar == 42); } void main() { }template is an Is this the name of the `mixin` or is the `template GenStruct` the name of what we pass to the `mixin`?The original code uses an eponymous template, which can be defined as "given a template definition that includes a symbol same as the template's name, that symbol will mean the same thing as instances of that template." So, in this case, the template instance GenStruct!("Foo", "bar") happens to be the same thing as the GenStruct member of that template.Can we create more than one const char[] in one `template` scopeYes.and what would it do if we could?1) The template would take advantage of those other symbols in its implementation: template GenStruct(string Name, string M1) { // Note: I would define both of these as 'enum's; // just staying with the same code style. const char[] memberDef = "int " ~ M1 ~ ";"; const char[] GenStruct = "struct " ~ Name ~ "{ " ~ memberDef ~ " }"; } 2) Members of a template can be used directly: // Defines two symbols template Foo(string s) { import std.format : format; enum integerVarDef = format!"int %s_i;"(s); enum doubleVarDef = format!"double %s_d;"(s); } // Mixing in one or the other symbol void main() { mixin(Foo!"hello".integerVarDef); hello_i = 42; mixin(Foo!"world".doubleVarDef); world_d = 1.5; } 3) All symbols can be mixed in as a whole. (Note it's a template mixin in this case as opposed to a string mixin.) template MemberListFeature(T) { T[] theList; void addMember(T value) { theList ~= value; } T getMember(size_t index) { return theList[index]; } } struct S { mixin MemberListFeature!string; // Now this struct has one member array and two member functions. } unittest { auto s = S(); s.addMember("hello"); s.getMember(0) == "hello"; } void main() { } etc. :)But nevertheless, I copied the code and changed it a bit to something like this: ```d template Vector(int dimension) { string cps = ""; foreach(d; 0..dimension) { cps ~= "x" ~ d ~ " = 0;\n"; } const char[] Vector = "struct Vector {\n" ~ dimension.to!string ~ cps ~ "}"; } ``` In my head a call to `mixin(Vector!5)` should result in something like this: ```d struct Vector5 { int x0; int x1; int x2; int x3; int x4; } ``` But it does not compile because `Error: declaration expected, not foreach` which I understand as "foreach is not possible during compile time",Not true. foreach *is* available at compile time but not in the template scope. (On the other hand, 'static foreach' is available inside a template scope or module scope, etc.) Here is an almost direct implementation of your idea: template Vector(int dimension) { import std.conv : to; string makeMembers() { // Note: No need to initialize with "" string cps; foreach(d; 0..dimension) { // Note: Initial values are not needed in D. // (Already initialized.) cps ~= "int x" ~ d.to!string ~ ";\n"; } return cps; } // Note: The name Vector would be confusing; changing to // VectorStruct const char[] Vector = "struct VectorStruct {\n" ~ makeMembers() ~ "}"; } // Note: Visualizing the result: pragma(msg, Vector!5); // Also see the compiler switch -mixin mixin(Vector!3); void main() { auto v = VectorStruct(); v.x0 = 0; v.x1 = 1; v.x2 = 2; } However, Vector vs. VectorStruct points at a problem there. Instead, here is another example that uses 'static foreach' and uses not a 'template' that defines a string but a 'struct template' directly: struct Vector(size_t dimension) { static foreach (d; 0..dimension) { import std.format : format; mixin (format!" int x%s;"(d)); } } void main() { auto v = Vector!3(); v.x0 = 0; v.x1 = 1; v.x2 = 2; }And as a final question. Let's say the above problems are all solved and I construct such a template. How could I build functions that take any of those `Vector`s as an argument? For example I want to add two of those, the function would look something like this, or am I lost again? ```d Vector!T add(Vector!T lhs, Vector!T rhs) { return ?; } ```T is a compile-time parameter there, which must be defined as such. I will stay with my size_t template parameter: struct Vector(size_t dimension) { static foreach (d; 0..dimension) { import std.format : format; mixin (format!" int x%s;"(d)); } } import std.stdio; void main() { auto a = Vector!2(1, 2); auto b = Vector!2(3, 4); auto c = add(a, b); writeln(c); } Vector!dim add(size_t dim)(Vector!dim lhs, Vector!dim rhs) { // As there are many different ways of implementing both Vector // and addition, I will just cheat and assume there is only // the x0 member: return Vector!dim(lhs.x0 + rhs.x0); }How could I iterate over all components if such a `Vector`?It is possible with .tupleof but unlike your design, I would use an int[dimension] static array in the implementation like I do with the Polygon struct template here: http://ddili.org/ders/d.en/templates_more.html Still, assuming the 'c' variable from the last example above exists, here is how .tupleof might be used: foreach (i, member; c.tupleof) { writefln!"Member %s is %s"(i, member); } Ali
Sep 27 2021
On Monday, 27 September 2021 at 17:14:11 UTC, Ali Çehreli wrote:On 9/27/21 9:23 AM, eXodiquas wrote:Sometimes I wonder if I should bother writing answers since one of you Old Guards make them redundant(and inadequate) :( I'm really surprised you went with his name-every-element-uniquely scheme though. Why didn't you recommend `static array`? Are there genuine use-cases where it makes more sense?You only mentioned it when it came to the traversal part.[...]Same here. :)[...]Often repeated but there are no stupid questions. [...]
Sep 27 2021
On 9/27/21 10:26 AM, Tejas wrote:On Monday, 27 September 2021 at 17:14:11 UTC, Ali =C3=87ehreli wrote:On 9/27/21 9:23 AM, eXodiquas wrote:Sometimes I wonder if I should bother writing answers since one of you=[...]Same here. :)[...]Often repeated but there are no stupid questions. [...]Old Guards make them redundant(and inadequate) :(Point taken.I'm really surprised you went with his name-every-element-uniquely scheme though. Why didn't you recommend `static array`? Are there genuine use-cases where it makes more sense?You only mentioned it when=it came to the traversal part.I noticed that too. ;) I could have changed other things there as well.=20 For example, I wanted to replace 'int' with 'size_t', which I did=20 eventually. I think staying with the original code as much as possible is helpful=20 for the OP to follow the response. Also, sometimes I miss what the=20 original intent is. :) Further, the original post touched on many concepts like eponymous=20 templates that I wanted to expand on instead of a short answer. Ali
Sep 27 2021
On Monday, 27 September 2021 at 17:43:22 UTC, Ali Çehreli wrote:On 9/27/21 10:26 AM, Tejas wrote:I was also already afraid of post length so I didn't write anything about `eponymous templates`... and instead threw in `partial template specialization`... Yeah I think you vets should still continue posting, I have a long way to go on making my posts accessible :/On Monday, 27 September 2021 at 17:14:11 UTC, Ali Çehreliwrote:one of youOn 9/27/21 9:23 AM, eXodiquas wrote:Sometimes I wonder if I should bother writing answers since[...]Same here. :)[...]Often repeated but there are no stupid questions. [...]Old Guards make them redundant(and inadequate) :(Point taken.I'm really surprised you went with hisname-every-element-uniquelyscheme though. Why didn't you recommend `static array`? Aretheregenuine use-cases where it makes more sense?You onlymentioned it whenit came to the traversal part.I noticed that too. ;) I could have changed other things there as well. For example, I wanted to replace 'int' with 'size_t', which I did eventually. I think staying with the original code as much as possible is helpful for the OP to follow the response. Also, sometimes I miss what the original intent is. :) Further, the original post touched on many concepts like eponymous templates that I wanted to expand on instead of a short answer. Ali
Sep 27 2021
On Monday, 27 September 2021 at 17:14:11 UTC, Ali Çehreli wrote:[...]Woah, thanks everyone for the ridiculous precise and helpful answers I got here. This forum never disappoints. :P I now try to fully understand the answers and implement the solution to the problem in a cleaner way. The reason I wanted to hold on to the single members, is because I implemented Vector2 and Vector3 by hand and I personally did not need higher dimensional vectors, but because I write this library as open source I could imagine some other developer may need more than 3 dimensions and it would be great if all those vectors behave exactly the same way. For example, the components of my `Vector2` are accessible via `v.x` and `v.y`. Otherwise I have to do something like `Vector4.components[0]` which doesn't look that nice imo. But with the new insight I got, I should be able to cook something up. Thanks again everyone. Have a great day, eXodiquas
Sep 27 2021
On Monday, 27 September 2021 at 16:23:50 UTC, eXodiquas wrote:Howdy ho everyone, I found this forum very helpful for my (maybe) stupid questions, so I give it a try again because I don't understand what's happening here. First of all, I'm not exactly sure what this code here, from the documentation at https://dlang.org/articles/mixin.html, does: ```d template GenStruct(string Name, string M1) { const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct!("Foo", "bar")); ``` In my understanding we create a template called `GenStruct` with compile time arguments `Name` and `M1`. We then create the `char[] GenStruct` which holds the source code for the `struct`. Afterwards we do the `mixin`call and create the source code during compile time to have it ready to go. But I don't understand why the `char[] GenStruct` is there. Is this the name of the `mixin` or is the `template GenStruct` the name of what we pass to the `mixin`? Can we create more than one const char[] in one `template` scope and what would it do if we could? So I'm a bit confused here. But nevertheless, I copied the code and changed it a bit to something like this: ```d template Vector(int dimension) { string cps = ""; foreach(d; 0..dimension) { cps ~= "x" ~ d ~ " = 0;\n"; } const char[] Vector = "struct Vector {\n" ~ dimension.to!string ~ cps ~ "}"; } ``` In my head a call to `mixin(Vector!5)` should result in something like this: ```d struct Vector5 { int x0; int x1; int x2; int x3; int x4; } ``` But it does not compile because `Error: declaration expected, not foreach` which I understand as "foreach is not possible during compile time", whereas I don't see any problem with compile time availability of anything in this template. Obviously I don't understand something here, so it would be awesome if someone could help me out here. :P And as a final question. Let's say the above problems are all solved and I construct such a template. How could I build functions that take any of those `Vector`s as an argument? For example I want to add two of those, the function would look something like this, or am I lost again? ```d Vector!T add(Vector!T lhs, Vector!T rhs) { return ?; } ``` How could I iterate over all components if such a `Vector`? I hope I am not on the completely wrong track to tackle this problem. Thanks in advance. :) eXodiquasYou are trying to write arbitrary statements inside a template, that will not work(if you insist on writing code that way, use [string mixins](http://ddili.org/ders/d.en/mixin.html)(please don't use them unless absolutely necessary) Now, to solve your problem: ```d struct Vector(int T){ int[T] elems; } ``` And that's it :D Now, how to use it? Here is an isolated code fragment: ```d auto Add(T: Vector!U,int U)(T a, T b){ /*Yes, you don't have to write different funcs for different instantiations of Vector :D*/ int[] c; c.length = U; for(size_t i = 0; i < U; i++){ c[i] = a.elems[i] + b.elems[i]; } return Vector!U(c); } ``` Full code: ```d import std; struct Vector(int t){ int[t] elems; size_t length = t; this(int[] input){ assert(input.length <= length); foreach(i,num; input){ elems[i] = num; } } this(int num){ elems = num; } void displayElems(){ import std.stdio; foreach(elem; elems){ writeln(elem); } } } auto Add(T: Vector!U,int U)(T a, T b){ int[] c; c.length = U; for(size_t i = 0; i < U; i++){ c[i] = a.elems[i] + b.elems[i]; } return Vector!U(c); } void main(){ auto first = Vector!10([7,896,864, 8976]); auto second = Vector!10([23,7890,9886]); auto third = Vector!10(5); auto result = Add(first, second); writeln(result); result.displayElems; third.displayElems; } ```
Sep 27 2021