Meta-programming - examples

janderson askme at me.com
Sat Feb 10 22:25:11 PST 2007


Andrei Alexandrescu (See Website For Email) wrote:
> janderson wrote:
>> mixin(statemachine(
>> "
>>     state FireAtEnemy
>>     {
>>         transition EnemyRange < 10
>>         {
>>             goto ChaseEnemy
>>         }
>>         transition FacingEnemy < .2
>>         {
>>             goto ChaseEnemy
>>         }
>>     }
>>
>>     state ChaseEnemy
>>     {
>>         ...
>>     }
>>
>> ");
>>
>> You might imagine doing the above with if statement and arrays of 
>> delegates however designers have a much harder time with that.
> 
> This example is eerily on target. A while ago I've enjoyed watching a 
> talk by Shriram Khrishnamurthi on... you gotta see it:
> 
> http://technetcast.ddj.com/tnc_play_stream.html?stream_id=644
> 
> Unfortunately, it looks like DDJ does not have the audio (which was 
> fantastic) anymore, so you can only see the slides (which are very good 
> as well). The slides 37 to 39 knocked my socks off so hard they stuck 
> onto the wall, and to this day I couldn't peel them away.
> 
> The way I'm seeing defining such DSLs is a bit more conservative than 
> yours: I'd let the D compiler do most of the parsing and I'd focus on 
> defining the state transitions:

Actually its very similar to a format that I've used in past games 
(except was a run-time thing).

> 
> class GameEngine
> {
>   mixin automaton!(
>     State!(FireAtEnemy,
>       ("EnemyRange < 10", "ChaseEnemy"),
>       ("FacingEnemy < .2", "ChaseEnemy")),
>     State!(ChaseEnemy,
>       ...)
>   )
> }


The difficulty with this approach is that its much harder to read and 
write, of course.  Also its harder to do global optimizations. 
Furthermore you can't type straight D code into it.  I'm seeing the 
statemachine as converting any code it doesn't understand into D code so 
you can use the power of D (for instance, you don't have to define 
operators for maths operations, you'd still be able to user for loops.).

Its seems like your trying to design around the limitations of the compiler.

Here's a version with mixed-in-D-Code.

mixin(statemachine(

import("Standard.behaviors") ~ //You could even reuse states like this
  "

      state FireAtEnemy
      {
          transition Me.DistanceToEnemy > 10 && Me.DistanceToEnemy < 20
          {
              goto ChaseEnemy
          }
          transition Me.FacingEnemy < .2
          {
              goto ChaseEnemy
          }
      }

      state ChaseEnemy
      {
         auto Direction = Enermy.Pos - Me.Pos;
	Me.SetFacing(Direction);

	if (EnemyRange > 20)
	{
		Me.Run();
	}
	else if (EnemyRange > 10)
	{
		Me.Walk();
	}
	else
	{
		Me.Stop();
		goto FireAtEnemy;
	}
      }

  ");

Note much of the time this would be done with an import.


> 
> It's amazing to think that D will allow this (actually already allows 
> with a slightly clunkier syntax). I'll make sure I'll be barefoot that 
> day. :o)
> 
>> 3D Object rendering
>>
>> //Render a 3D model.  For instance this may generate the vertexbuffers 
>> and textures directly into code, or may extract some of the data from 
>> the 3Dmodel.obj and load the rest at run-time.
>> mixin(renderModel(import("3Dmodel.obj")));
>>
>> Transforming Textures
>> DXDtexture* texture = mixin(textureToD3D(import("3Dmodel.bmp")));
> 
> Sounds great, but no expertise to comment on that.
> 
>> Simplify saving/loading of arbitrary structures.
>>
>> //Only write this once.  Things are re-ordered for best fit in memory, 
>> localization ect...
>> mixin(Serailzable("Ship",
>> "
>>     struct Part
>>     {
>>         float firePower;
>>         char[] Model;
>>     }
>>
>>     struct Ship
>>     {
>>         bool Friendly;
>>         Part Parts[];
>>     }
>> ");
>>
>> ... Later
>>
>> Load("Ship", "Ship.asset");
> 
> Yah, this has been pointed out indeed. Also add remote procedure calls. 
> Generating all of the marshaling/unmarshaling code (for various 
> standards!) will be trivially done by libraries. I actually see PyD as a 
> great first application of that concept that will spark many others.
> 
>> GUI -> not sure about this one as I can't come up with a format thats 
>> much neater then straight code. I'll post it anyways.
>>
>> mixin(MyGUI(
>> "
>>     Button "OK", 10, 30
>>     {
>>         Exit;
>>     }
>> ");
> 
> Great. The problem with GUI programming has always been that programming 
> language is not a natural vehicle for specifying forms and stuff. Many 
> frameworks have relied on some framework for code generation and 
> impedance matching (Tcl/Tk, Windows resources, ...) with various levels 
> of awkwardness. Due to its compile-time manipulation abilities, D will 
> make it trivial to bind GUI resources to D code.
> 
> The way I see this happening is more along the lines:
> 
> mixin(import "inputform.rc")
> 

I see both.  You can enter it directly when you want to do a little bit 
of code or proto-typing, and use import when u need that.

> The file can be generated and edited with other tools (e.g. gui 
> designers). That's why I insisted with Walter that strings should be 
> importable from files. This effectively makes you benefit of the dual 
> cake paradox, in that at the same time you have the advantage of 
> separate files for separate languages, and the advantage of seamless 
> integration between them.
> 
>> Multi-threading
>>
>> The suggestion with multi-threading I came up with a little while ago:
>>
>> int[] array ...
>> int result = 0;
>> mixin(threadIt(
>> "
>>     foreach(A a; array)
>>     {
>>         result += a;
>>     }
>>     combiner //If necessary?
>>     {
>>         result = result[0] + result[1];
>>     }
>> ");
>>
>> Compile time checking of code for coding standards or what have u:
> 
> I'm not understanding this.

What part?

> 
>> mixin(CheckCode("
>>
>> ect...
>>
>>
>> ");
>> //Note that there should be a way to disable CheckCode in the general 
>> case to save compile time
> 
> I guess this is an obvious:
> 
> mixin(CheckCode(import "program.d"));

Exactly, both would be supported.  Sometimes its useful to have code in 
the same context that its been used.  Sometimes not.

> 
> A file containing a mixin for each program in a project can be generated 
> by the build process.
> 
>> There's heaps of other stuff, but that would make this post way to long.
> 
> There's always the opportunity of a next post :o).

Actually, the real reason is I'm just lazy.

> 
> Stay tuned. Compilation times will come down dramatically. Walter is up 
> to something pretty cool, but it will take a while. 

This is great news

 > Advice: don't wear socks when reading d.announce :o).

I'm taking them off now.

> 
> Andrei



More information about the Digitalmars-d mailing list