Amusing D facts: typesafe variadic arrays are lazy!

downs default_357-line at yahoo.de
Wed Oct 14 00:17:58 PDT 2009


Jeremie Pelletier wrote:
> Andrei Alexandrescu wrote:
>> Chris Nicholson-Sauls wrote:
>>> downs wrote:
>>>>
>>>> Here is a funny consequence of this amusing fact:
>>>>
>>>> if you overload opAssign in a struct with lazy T[] dgs..., you can
>>>> achieve the following syntax
>>>>
>>>>
>>>>>     WithFlag(GL_BLEND, true) = WithDepthMask(false) = tex.With =
>>>>> Quads = {
>>>>>       foreach (i, q; qa) {
>>>>>         float f = 1f*i / qa.length; Color(1f-f, f, 1f);
>>>>>         TexCoord(0f, 0f); Vertex(q.points[0]);
>>>>>         TexCoord(1f, 0f); Vertex(q.points[1]);
>>>>>         TexCoord(1f, 1f); Vertex(q.points[3]);
>>>>>         TexCoord(0f, 1f); Vertex(q.points[2]);
>>>>>       }
>>>>>     };
>>>
>>> That's... just beautiful...
>>>
>>> -- Chris Nicholson-Sauls
>>
>> Not getting it... could someone please explain?
>>
>> Andrei
> 
> From what I get, he has something like this:
> 
> struct WithFlag(int OP, bool enable) {
>     static void opAssign(T)(lazy T next) {
>         static if(enable) glEnable(OP);
>         else glDisable(OP);
>         next();
>     }
> }
> 
> struct WithDepthMask(bool enable) {
>     static void opAssign(T)(lazy T next) {
>         glDepthMask(enable);
>         next();
>     }
> }
> 
> struct Tex {
>     void opAssign(T)(lazy T next) {
>         glBindTexture(_tex);
>         next();
>     }
> }
> 
> struct Quads {
>     static void opAssign(T)(lazy T commands) {
>         glBegin(GL_QUADS);
>         commands();
>         glEnd();
>     }
> }
> 
> I don't know if thats his exact code, but from what I can remember of gl
> from memory it should look like this.
> 
> Jeremie

Very close. There's another workaround required to enable the = {} syntax.


The T in question can either be a void, in which case we're assigning a function call, or a void delegate(), in which case we're assigning a subscope.

Because the parameter is lazy, in the case of void delegate() we actually have to call it doubly nestedly!

This leads to the following code.

> const string LazyCall="
> static if (is(T==void)) t();
> else static if (is(T==void delegate())) t()();
> else static assert(false, T.stringof);
> ";

...


> template PrimitiveScope(string NAME, string WHICH) {
>   const string PrimitiveScope="struct "~NAME~" {
>     static void opAssign(T)(lazy T t) {
>       glBegin("~WHICH~"); scope(exit) glEnd();
>       "~LazyCall~"
>     }
>   }";
> }

...

> mixin(Concat!(MAP!(PrimitiveScope, 2,
>   "Points", "GL_POINTS", "Lines", "GL_LINES",
>   "LineLoop", "GL_LINE_LOOP", "LineStrip", "GL_LINE_STRIP",
>   "Triangles", "GL_TRIANGLES", "TriangleStrip", "GL_TRIANGLE_STRIP",
>   "TriangleFan", "GL_TRIANGLE_FAN", "Quads", "GL_QUADS",
>   "QuadStrip", "GL_QUAD_STRIP", "Polygon", "GL_POLYGON"
> )));

:deranged grin: I love templates!



More information about the Digitalmars-d mailing list