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