How to create mixin template and pass name of a variable?

Bosak bosak at gmail.com
Fri Aug 2 06:46:40 PDT 2013


On Friday, 2 August 2013 at 12:47:51 UTC, monarch_dodra wrote:
> On Friday, 2 August 2013 at 12:17:12 UTC, Bosak wrote:
>> On Friday, 2 August 2013 at 12:10:00 UTC, Bosak wrote:
>>> On Friday, 2 August 2013 at 11:52:32 UTC, monarch_dodra wrote:
>>>> On Friday, 2 August 2013 at 11:37:27 UTC, Bosak wrote:
>>>>> I want to create a mixin template such that:
>>>>>
>>>>> mixin template ArgNull(alias arg, string name)
>>>>> {
>>>>> if(arg is null)
>>>>>     throw new Exception(name~" cannot be null.");
>>>>> }
>>>>>
>>>>> But is there a way to do that with only one template 
>>>>> argument. And then use it like:
>>>>>
>>>>> string text = null;
>>>>> mixin ArgNull!(text);
>>>>>
>>>>> And the above mixin to make:
>>>>>
>>>>> if(text is null)
>>>>> throw new Exception("text cannot be null.");
>>>>
>>>> A mixin template can't inject arbitrary code (AFAIK), but 
>>>> only members/functions/structs etc.
>>>>
>>>> A simple string mixin would solve what you need better 
>>>> anyways:
>>>>
>>>> import std.stdio, std.typetuple, std.string;
>>>>
>>>> //----
>>>> template ArgNull(alias name)
>>>> {
>>>>  enum ArgNull = format(q{
>>>>     if(%1$s is null)
>>>>         throw new Exception("%1$s cannot be null.");
>>>>  }, name.stringof);
>>>> }
>>>>
>>>> void main()
>>>> {
>>>>  string s1 = "hello";
>>>>  string s2;
>>>>
>>>>  mixin(ArgNull!s1);
>>>>  mixin(ArgNull!s2);
>>>> }
>>>> //----
>>>>
>>>> FYI, "q{}" is called a "token string", and is formidably 
>>>> useful to write a string that contains code. Also, I'm 
>>>> exploiting the alias arg to extract the name out of the 
>>>> variable. This makes it impossible to accidentally call the 
>>>> mixin with an invalid string (the error will be *at* the 
>>>> mixin call, not *in* the mixin call).
>>>
>>> Oh I like your solution. It is just what I needed, thanks! 
>>> Also I didn't knew you could make enums that contain string 
>>> values. So in D enums are like constants in C#, right? I see 
>>> that enums are used a lot with templates. And why is the name 
>>> of the enum the same with the name of the template? Does it 
>>> allways have to be like that?
>
> In D, you can type enums, and string is part of the types 
> compatible.
>
> enum food : string
> {
>     burger = "burger",
>     pie = "pie",
> }
>
> That said, this is not what is going on here. What you are 
> seeing is known as "manifest constant". They keyword "enum" 
> means: "This "variable" is a compile-time know name".
>
> EG:
> enum N = 25; //N is a *keyword* known by the compiler
> int  M = 32; //M is just some variable
> int[N] arr1; //OK
> int[M] arr2; //Error: variable M cannot be read at compile time
>
> This brings us to templates. A "template" isn't an object in 
> itself, but rather, a namespace that can hold tons of useful 
> stuff. Unlike a namespace though, a template can be 
> parameterized. This means basically, you can have the namespace 
> "foo!int" and the namespace "foo!string" for example.
>
> This scheme becomes fun once you mix CTFE into this. CTFE means 
> "compile time function evaluation", which means your function 
> is run *while* your program is compiling. This is cool because 
> you can store the result, and the compiler *knows* the result.
>
> A very simple template could be:
>
> template Hello(alias name)
> {
>     enum String = "Hello " ~ name;
> }
>
> First, you create the namespace Hello!"bob", and then you can 
> extract String to obtain "Hello bob".
>
> Templates most often contain enums or Aliases, but sometimes, 
> also functions, or new types.
>
> As you can see though, adding ".String" is a bit of a pain. 
> That's where "eponymous" templates come in. By making an 
> object/alias carry the same name as the template, then the 
> template *becomes* that alias directly.
>
> If we go back to the above example, and write it as:
> template Hello(alias name)
> {
>     enum Hello = "Hello " ~ name;
> }
>
> In this case, Hello!"bob" *is* the string "Hello bob". You now 
> have a parameterized string(!) You can use it:
> string hello_bob = Hello!"bob";
> But what is coolest is that the compiler knows this too, so you 
> can mix it in too, or whatever.
>
> This is exactly what I did. My template name is ArgNull. 
> Instead of doing a "simple" string operation, I used the 
> function format, which can be evaluated CTFE. There's not much 
> magic going on.
>
> I hope it wasn't too much? These techniques in meta-programming 
> are a bit hard to write and master, but the idea is that 
> *useage* should be straight forward.
>
>> Also is there a way to see my code after mixins, templates and 
>> CTFE gets executed? Like some kind of compiler switch or 
>> something?
>
> This is currently being discussed and worked on, but as of 
> today, no.

Thanks a lot for your explanation. Now enums and templates are a 
lot more clear to me!



More information about the Digitalmars-d-learn mailing list