mixin templates with name parameter

js.mdnq js_adddot+mdng at gmail.com
Fri Nov 30 05:16:17 PST 2012


On Friday, 30 November 2012 at 04:04:10 UTC, Ali Çehreli wrote:
> On 11/29/2012 05:08 PM, js.mdnq wrote:
>> mixin templates seems like they could benefit from an extra 
>> parameter
>> that one can pass a name. The name, a string literal, sort of 
>> acts like
>> a preprocessor token:
>>
>> mixin template InjectX!(T)
>> {
>> private T x;
>> T get#name#( ) { return x; }
>> void set#name#(T y)
>> {
>> // Checks
>> x = y;
>> }
>> }
>>
>> Then something like "mixin InjectX!int Mylnt;" will create the 
>> following
>> function
>>
>> getMylnt and setMylnt.
>>
>> The scope names are a nice solution and sometimes what one 
>> wants. But
>> sometimes one would like to avoid an extra referencing step.
>>
>> In fact, it would be nice if one could inject code into the 
>> template
>> code. One, could example, even supply an object or another 
>> mixin with
>> the mixin to compose the code. If, say, I wanted slightly 
>> different set
>> functions above I would have to write a template for each one, 
>> but if I
>> code compose mixins then I could avoid that.
>>
>> In any case, it can get rather complicated and notation is the 
>> key
>> issue(how to describe it all elegantly). I think the idea and 
>> the way D
>> does it is pretty elegant though and probably good enough for 
>> most
>> cases. I just imagine cases where a very complex mixin might 
>> need slight
>> changes from one use to the next but unfortunately would 
>> require some
>> inelegant methods to use it.
>>
>> Possibly one could compose mixins in a way that all common 
>> function
>> overlap are serialized.
>>
>> "alias mixin InjectX!int with InjectY!int Mylntalias;"
>> "mixin MyIntalias!int MyInt;"
>>
>> will produce a mixin s.t., the set functions of Y are 
>> serialized with
>> those of X. (the new set function will first call the set of 
>> InjectY
>> then that of InjectX)
>>
>> This way, we can "extend" a mixin relatively easy by simply 
>> "appending"
>> code to it's functions.
>>
>>
>> Just some food for thought.
>>
>
> There are also string mixins, which provide some help:
>
> string getFunction(string name)()
> {
>     return "T get" ~ name ~ "( ) { return x; }";
> }
>
> string setFunction(string name)()
> {
>     return "void set" ~ name ~ "(T y)" ~ q{
>         {
>             // Checks
>             x = y;
>         }
>     };
> }
>
> string varDeclaration(string name)()
> {
>     return "private T " ~ name ~ ";";
> }
>
> template InjectX(T, string name)
> {
>     mixin (varDeclaration!name);
>     mixin (getFunction!name);
>     mixin (setFunction!name);
> }
>
> class C
> {
>     mixin InjectX!(int, "x");
> }
>
> void main()
> {
>     auto c = new C;
>     c.getx();
>     c.setx(42);
> }
>
> There is a warning though: The current compiler is very slow 
> when there are too many little string mixins. I heard that one 
> large function that generates all three string above would be 
> way faster than the three that I have used.
>
> Ali

Yeah, it's a bit "stringy" for my tastes but it does provide a 
solution.

I suppose one can actually store the templates in another file 
and parse them beforehand(sort of preprocessing) and just replace 
all occurrences of #name# with the name provided? e.g.,

templates = import("templates.dtp")
mixin parsename(templates, "myname");

(just pseudo code, I don't know enough about D yet to get it to 
work)

templates.dtp would be normal template mixins(not stringified) 
except using #name# as a name token. parsename will simply 
replace #name#(or whatever symbol used) with the 2nd parameter. 
mixin will mix it in as normal.









More information about the Digitalmars-d mailing list