Mixed up over mixins.

Johnson Jones via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Aug 20 15:50:40 PDT 2017


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.





















More information about the Digitalmars-d-learn mailing list