www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Mixed up over mixins.

reply WhatMeWorry <kheaser gmail.com> writes:
It's stuff like this which makes me very frustrated. Or depressed 
because it demonstrates just how poor a programmer I am:


string printStatement(string message) {
     return `writeln("` ~ message ~ `");`;
}

void main()
{
     // Mixins are for mixing in generated code into the source 
code.
     // The mixed in code may be generated as a template instance
     // or a string.

     mixin(printStatement("hello world"));
     mixin(`writeln(` ~ `Hello`  ~ `);` );
     mixin("writeln(`World`);");	
}

Compiling gives me the errors:

Error: undefined identifier Hello

To me, `writeln(` ~ `Hello`  ~ `);` is a valid D string? Okay, 
maybe a
string expression but a string nevertheless.

So, am I giving mixin more magical powers than it possesses?

Should we say that mixin needs to be given a "fully pre-formed D 
compilable" string?

Thanks. especially to let me vent.
Aug 20
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 08/20/2017 12:27 PM, WhatMeWorry wrote:

     // Mixins are for mixing in generated code into the source code.
     // The mixed in code may be generated as a template instance
     // or a string.
Yes, it means that the string must be legal D code.
     mixin(`writeln(` ~ `Hello`  ~ `);` );
Yes, that's a D string but the string itself is not legal D code because it would be mixing in the following: writeln(Hello); The problem is, there is no Hello defined in the program. You need to make sure that Hello is a string itself: writeln("Hello"); So, you need to use the following mixin: mixin(`writeln(` ~ `"Hello"` ~ `);` ); Ali
Aug 20
parent reply WhatMeForget <kheaser gmail.com> writes:
On Sunday, 20 August 2017 at 19:41:14 UTC, Ali Çehreli wrote:
 On 08/20/2017 12:27 PM, WhatMeWorry wrote:

     // Mixins are for mixing in generated code into the
source code.
     // The mixed in code may be generated as a template
instance
     // or a string.
Yes, it means that the string must be legal D code.
     mixin(`writeln(` ~ `Hello`  ~ `);` );
Yes, that's a D string but the string itself is not legal D code because it would be mixing in the following: writeln(Hello); The problem is, there is no Hello defined in the program. You need to make sure that Hello is a string itself: writeln("Hello"); So, you need to use the following mixin: mixin(`writeln(` ~ `"Hello"` ~ `);` ); Ali
Of course, why didn't I "see" that before. I should have slept on it and tried again with fresh eyes. I'm keeping a "beginners journal" on code generation. Maybe write a 101 introduction with lots of samples and exercises. Thanks. Don't know if you noticed, but i used some code from your book. Hope you take that as a complement.
Aug 21
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/21/17 3:29 AM, WhatMeForget wrote:
 On Sunday, 20 August 2017 at 19:41:14 UTC, Ali Çehreli wrote:
 On 08/20/2017 12:27 PM, WhatMeWorry wrote:

     // Mixins are for mixing in generated code into the
source code.
     // The mixed in code may be generated as a template
instance
     // or a string.
Yes, it means that the string must be legal D code.
     mixin(`writeln(` ~ `Hello`  ~ `);` );
Yes, that's a D string but the string itself is not legal D code because it would be mixing in the following: writeln(Hello); The problem is, there is no Hello defined in the program. You need to make sure that Hello is a string itself: writeln("Hello"); So, you need to use the following mixin: mixin(`writeln(` ~ `"Hello"` ~ `);` );
Of course, why didn't I "see" that before. I should have slept on it and tried again with fresh eyes. I'm keeping a "beginners journal" on code generation. Maybe write a 101 introduction with lots of samples and exercises.
When doing mixins, especially when the code to generate the mixin string isn't a simple literal, a great thing to do is to use pragma(msg) to show the actual string you are mixing in. e.g.: enum mixinstr = ... pragma(msg, mixinstr); mixin(mixinstr); Often times, your error is obvious when you see it that way. -Steve
Aug 21
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 08/21/2017 12:29 AM, WhatMeForget wrote:

 Thanks. Don't know if you noticed, but i used some code from your book.
 Hope you take that as a complement.
I did notice that and thank you. Every time I see people struggle with code that originated from my half-witted examples, I actually feel guilty. :) Ali
Aug 21
prev sibling parent reply Johnson Jones <JJ Dynomite.com> writes:
On Sunday, 20 August 2017 at 19:27:43 UTC, WhatMeWorry wrote:
 It's stuff like this which makes me very frustrated. Or 
 depressed because it demonstrates just how poor a programmer I 
 am:


 string printStatement(string message) {
     return `writeln("` ~ message ~ `");`;
 }

 void main()
 {
     // Mixins are for mixing in generated code into the source 
 code.
     // The mixed in code may be generated as a template instance
     // or a string.

     mixin(printStatement("hello world"));
     mixin(`writeln(` ~ `Hello`  ~ `);` );
     mixin("writeln(`World`);");	
 }

 Compiling gives me the errors:

 Error: undefined identifier Hello

 To me, `writeln(` ~ `Hello`  ~ `);` is a valid D string? Okay, 
 maybe a
 string expression but a string nevertheless.

 So, am I giving mixin more magical powers than it possesses?

 Should we say that mixin needs to be given a "fully pre-formed 
 D compilable" string?

 Thanks. especially to let me vent.
It's not difficult, it's just new. It's not that you are a poor programmer, but you simply have not learned how to think about mixins correctly. Stop whining about it and focus that energy on working with them. String mixins are very simple. It takes any string and inserts it as code in to the program directly as if you typed it by hand. What makes them useful is that you can build strings a compile time and so essentially introduce compile time code generation. e.g., L324: mixin("Hello World") becomes L324: Hello World and so mixin(N) gets inserted as N, as if you typed it in directly. (this is the important part. N isn't inserted but the contents of N as a string. What this is good for, is say you want to generate code based off stuff at compile time, e.g., a configuration file. You can generate valid D code using strings that load the configuration file at compile time and do what you want with it. e.g., enum config = import(myconfigfile); config now contains, as a string, the contents of myconfigfile AT COMPILE TIME. Normally we think of config as being a run time variable, but it is simply a compile time variable(well, it can't vary, unfortunately, the compile time processing is not a fully integrated compile time compiler. enum configCode = process(config); let process be a function that takes config, extracts the data from it and bundles it all up in new D code. mixin(configCode); Now mixes in that code direct in to the source as if we typed it. e.g., enum classes = import("classNames"); string code; foreach(n; classes.split(",")) code ~= "class "~n~";\n"; // at this point code should be something like "class X;\nclass Y;" etc, but it depends on the file. mixin(code); has the same effect if we typed class X; class Y; But the difference is that we used a file to extract the class names and a string mixin that inserted the code. This way we don't have to manually change the class names in our D file, we just change the classNames file, which is probably autogenerated anyways. String mixins come in very handy when you have D code that can be "generalized" (parameterized). It's sort of the place holder concept: You have a D string like " if (alpha_1 > 0) { Alpha1(); } if (alpha_2 > 0) { Alpha2();} if (alpha_3 > 0) { Alpha3();} if (alpha_4 > 0) { Alpha4();} " ... Obviously if you can simplify all that code it would be nice, well you can! for(int i = 0; i < N; i++) mixin("if (alpha_"~i~" > 0) { Alpha"~i~"();}"); this will mix N of those lines with the proper mapping. I only have to make one change rather than N. You have to think of them as D code generators. Of course, you don't have to use them to generate code, but they are insert, foremost, in D code and will be interpreted by the D compiler. mixin("string X = \"mixin string X = \""mixin string X = \"""mixin string X = .....); is the same as string X = \"mixin string X = \""mixin string X = \"""mixin string X = .....""""; and, if we used enums(compile time object) instead of strings(run time object), we could do mixin(X); and it would mix in the next layer, which would redfine X each time. It's not difficult, just requires a different way to think about them, as does anything that is unfamiliar.
Aug 20
parent reply WhatMeForget <kheaser gmail.com> writes:
On Sunday, 20 August 2017 at 22:50:40 UTC, Johnson Jones wrote:
 On Sunday, 20 August 2017 at 19:27:43 UTC, WhatMeWorry wrote:
 [...]
It's not difficult, it's just new. It's not that you are a poor programmer, but you simply have not learned how to think about mixins correctly. Stop whining about it and focus that energy on working with them. [...]
Thank you. You have rejuvenated my quest for mixin mastery :)
Aug 21
parent Johnson <Johnson Johnson.com> writes:
On Monday, 21 August 2017 at 07:34:23 UTC, WhatMeForget wrote:
 On Sunday, 20 August 2017 at 22:50:40 UTC, Johnson Jones wrote:
 On Sunday, 20 August 2017 at 19:27:43 UTC, WhatMeWorry wrote:
 [...]
It's not difficult, it's just new. It's not that you are a poor programmer, but you simply have not learned how to think about mixins correctly. Stop whining about it and focus that energy on working with them. [...]
Thank you. You have rejuvenated my quest for mixin mastery :)
Just stick with it ;) Things will click. The more you trudge through them and just try to immerse yourself in it the faster it will happen. I use mixins all the time because they are a great way to simplify code... although actually writing them can be a pain because you can't debug them in any sane way. Remember, that you will generally use string generation a ton because that is mainly what you are working. Sometimes, for complex tasks I might have to write a function that I run at runtime like a normal program that takes in a string and outputs it. This lets me debug properly. As long as one doesn't use crazy io(even file IO is blocked ;/) the same function can be run at compile time(CTFE). This means myfoo("asdfasdf"); will be ran at compile time, the reason is simply that the input is constant, there are no side effects, and so the output can be computed at compile time. But the same function can be debugged if ran at runtime... and remember, the output is a string, so you can just print it out, no mixin is occuring at this point. The idea is that you make sure the string output is going to be the correct D code you want to mixin. It should look like normal D code, because if you do a mixin on it, it has to be to compile. Any syntax errors will be picked up and you'll be hunting them down because D will give you an obtuse error rather than a specific line number in the mixin(this is a severe issue with D but no one seem to care). If you debugged at runtime, you will get a line number where the error occurred, which is why you go that route. Once you've gotten your function written to do the code, you simply wrap a mixin() around it, you might have to change a bit of runtime to compile time stuff(file io to import) and then all that string stuff that you generated becomes D code! mixin("int i = 3"); <- bug mixin("int i = 3;"); <- ok same as int i = 3; useless example but sometimes it's helpful. Sometimes to get the things working you have to use mixins of mixins: mixin("mixin("~something~");"); or, take this example auto alpha = "hello"; mixin("w"~"r"~"i"~"te(`"~alpha~"`);"); before the mixin we have "w"~"r"~"i"~"te(`"~alpha~"`);" which, when simplified is "write(`"~alpha~"`);" which, since alpha is a constant, we have "write(`hello`);" which, the mixin simply does write(`hello`); which is now D code. A mixin, in a sense, just "unstringifies" it's argument and inserts it directly in to the source code... it better be valid code, which also means the string better be a valid string of D code.
Aug 21