www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - mixin extension

reply Matthias Spycher <matthias coware.com> writes:
Here's an idea to extend mixins in a manner that would allow you to mix 
code around a block in D.

If you had:

template Trace(f:char[])
{
   printf("Entering %s", f);
}
{
   printf("Exiting %s", f);
}

Note the two blocks associated with a single template declaration. You 
might mix code around a third block with:

void test()
{
   mixin Trace!("test") {
     do_something();
     more_here();
   }
}

resulting in the equivalent of:

void test()
{
   printf("Entering %s", f);
   do_something();
   more_here();
   printf("Exiting %s", f);
}

Ideally, such a construct could be used in conjunction with a 
conditional version statement:

void test()
{
   version (Log) mixin Trace!("test") {
     do_something();
     more_here();
   }
}

which when logging is disabled would evaluate to:

void test()
{
   do_something();
   more_here();
}

Is this feasible? Are there better ways?

Matthias
May 03 2006
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Howdy.

Matthias Spycher wrote:
 Here's an idea to extend mixins in a manner that would allow you to mix
 code around a block in D.
 
 If you had:
 
 template Trace(f:char[])
 {
   printf("Entering %s", f);
 }
 {
   printf("Exiting %s", f);
 }
How about this instead: template Trace(f:char[], block inner_block) { writefln("Entering %s", f); inner_block; writefln("Exiting %s", f); } That way, you can also support more complicated constructs like this: template Repeat(int times, block inner_block) { for( int i=0; i<times; i++ ) inner_block; } Of course, the problem with this is that templates only allow for declarations, not arbitrary statements. Perhaps we could then add the following, which would mix a block into the instantiating scope: template Repeat(int times, block inner_block) { block Repeat { for( int i=0; i<times; i++ ) inner_block; } }
 
 Note the two blocks associated with a single template declaration. You
 might mix code around a third block with:
 
 void test()
 {
   mixin Trace!("test") {
     do_something();
     more_here();
   }
 }
 
Personally, I'd like to be able to drop the "mixin" keyword. I realise that semantically, it makes sense since you're mixing the contents of the template in, but without it, it just looks cooler :) void test() { Trace!("test") { do_something(); more_here(); } }
 resulting in the equivalent of:
 
 void test()
 {
   printf("Entering %s", f);
   do_something();
   more_here();
   printf("Exiting %s", f);
 }
 
 Ideally, such a construct could be used in conjunction with a
 conditional version statement:
 
 void test()
 {
   version (Log) mixin Trace!("test") {
     do_something();
     more_here();
   }
 }
 
 which when logging is disabled would evaluate to:
 
 void test()
 {
   do_something();
   more_here();
 }
 
 Is this feasible? Are there better ways?
 
 Matthias
I'll steal a Pythonism, and vote +1. This would be *really* handy, and it would allow for the creation of almost arbitrary control structures! For the longest time, I've had evil thoughts of making a D preprocessor that only operated on complete, valid parse trees. It would basically be a D compiler that read in D, modified it in some way, then spat it back out. With that, you could make structures like this: fori( int i; 10 ) block; Which would be "expanded" by the preprocessor as: for( int i=0; i<10; i++ ) block; But using the above idea, you could just write this as a template: template fori(alias variable, int limit, block inner) { block fori { for( variable = 0; variable < limit; variable++ ) inner; } } Of course, this would be helped if we could drop in arbitrary symbols or declarations, but I can live without that :) -- Daniel "Must... have... meta... programming..." Keep -- v1sw5+8Yhw5ln4+5pr6OFma8u6+7Lw4Tm6+7l6+7D a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 03 2006
next sibling parent Hasan Aljudy <hasan.aljudy gmail.com> writes:
Passing a block of code to a template is a nice and original idea.
Overall, I like it, and it gets my vote.


Daniel Keep wrote:
 Howdy.
 
 Matthias Spycher wrote:
 
Here's an idea to extend mixins in a manner that would allow you to mix
code around a block in D.

If you had:

template Trace(f:char[])
{
  printf("Entering %s", f);
}
{
  printf("Exiting %s", f);
}
How about this instead: template Trace(f:char[], block inner_block) { writefln("Entering %s", f); inner_block; writefln("Exiting %s", f); } That way, you can also support more complicated constructs like this: template Repeat(int times, block inner_block) { for( int i=0; i<times; i++ ) inner_block; } Of course, the problem with this is that templates only allow for declarations, not arbitrary statements. Perhaps we could then add the following, which would mix a block into the instantiating scope: template Repeat(int times, block inner_block) { block Repeat { for( int i=0; i<times; i++ ) inner_block; } }
Note the two blocks associated with a single template declaration. You
might mix code around a third block with:

void test()
{
  mixin Trace!("test") {
    do_something();
    more_here();
  }
}
Personally, I'd like to be able to drop the "mixin" keyword. I realise that semantically, it makes sense since you're mixing the contents of the template in, but without it, it just looks cooler :) void test() { Trace!("test") { do_something(); more_here(); } }
resulting in the equivalent of:

void test()
{
  printf("Entering %s", f);
  do_something();
  more_here();
  printf("Exiting %s", f);
}

Ideally, such a construct could be used in conjunction with a
conditional version statement:

void test()
{
  version (Log) mixin Trace!("test") {
    do_something();
    more_here();
  }
}

which when logging is disabled would evaluate to:

void test()
{
  do_something();
  more_here();
}

Is this feasible? Are there better ways?

Matthias
I'll steal a Pythonism, and vote +1. This would be *really* handy, and it would allow for the creation of almost arbitrary control structures! For the longest time, I've had evil thoughts of making a D preprocessor that only operated on complete, valid parse trees. It would basically be a D compiler that read in D, modified it in some way, then spat it back out. With that, you could make structures like this: fori( int i; 10 ) block; Which would be "expanded" by the preprocessor as: for( int i=0; i<10; i++ ) block; But using the above idea, you could just write this as a template: template fori(alias variable, int limit, block inner) { block fori { for( variable = 0; variable < limit; variable++ ) inner; } } Of course, this would be helped if we could drop in arbitrary symbols or declarations, but I can live without that :) -- Daniel "Must... have... meta... programming..." Keep
May 03 2006
prev sibling next sibling parent Matthias Spycher <matthias coware.com> writes:
Hi Daniel,

I thought about passing blocks into templates as well, but I think we'd 
be getting too close to lisp doing this sort of thing. No doubt it's a 
very powerful construct. I was thinking about code weaving and 
aspect-oriented programming, etc., and I find that conditionally mixing 
in code around some block is a rather frequent pattern.

Matthias

Daniel Keep wrote:
 Howdy.
 
 Matthias Spycher wrote:
 Here's an idea to extend mixins in a manner that would allow you to mix
 code around a block in D.

 If you had:

 template Trace(f:char[])
 {
   printf("Entering %s", f);
 }
 {
   printf("Exiting %s", f);
 }
How about this instead: template Trace(f:char[], block inner_block) { writefln("Entering %s", f); inner_block; writefln("Exiting %s", f); } That way, you can also support more complicated constructs like this: template Repeat(int times, block inner_block) { for( int i=0; i<times; i++ ) inner_block; } Of course, the problem with this is that templates only allow for declarations, not arbitrary statements. Perhaps we could then add the following, which would mix a block into the instantiating scope: template Repeat(int times, block inner_block) { block Repeat { for( int i=0; i<times; i++ ) inner_block; } }
 Note the two blocks associated with a single template declaration. You
 might mix code around a third block with:

 void test()
 {
   mixin Trace!("test") {
     do_something();
     more_here();
   }
 }
Personally, I'd like to be able to drop the "mixin" keyword. I realise that semantically, it makes sense since you're mixing the contents of the template in, but without it, it just looks cooler :) void test() { Trace!("test") { do_something(); more_here(); } }
 resulting in the equivalent of:

 void test()
 {
   printf("Entering %s", f);
   do_something();
   more_here();
   printf("Exiting %s", f);
 }

 Ideally, such a construct could be used in conjunction with a
 conditional version statement:

 void test()
 {
   version (Log) mixin Trace!("test") {
     do_something();
     more_here();
   }
 }

 which when logging is disabled would evaluate to:

 void test()
 {
   do_something();
   more_here();
 }

 Is this feasible? Are there better ways?

 Matthias
I'll steal a Pythonism, and vote +1. This would be *really* handy, and it would allow for the creation of almost arbitrary control structures! For the longest time, I've had evil thoughts of making a D preprocessor that only operated on complete, valid parse trees. It would basically be a D compiler that read in D, modified it in some way, then spat it back out. With that, you could make structures like this: fori( int i; 10 ) block; Which would be "expanded" by the preprocessor as: for( int i=0; i<10; i++ ) block; But using the above idea, you could just write this as a template: template fori(alias variable, int limit, block inner) { block fori { for( variable = 0; variable < limit; variable++ ) inner; } } Of course, this would be helped if we could drop in arbitrary symbols or declarations, but I can live without that :) -- Daniel "Must... have... meta... programming..." Keep
May 04 2006
prev sibling parent David Medlock <noone nowhere.com> writes:
Daniel Keep wrote:
 Howdy.
 
 Matthias Spycher wrote:
 Here's an idea to extend mixins in a manner that would allow you to mix
 code around a block in D.

 If you had:

 template Trace(f:char[])
 {
   printf("Entering %s", f);
 }
 {
   printf("Exiting %s", f);
 }
How about this instead: template Trace(f:char[], block inner_block) { writefln("Entering %s", f); inner_block; writefln("Exiting %s", f); } That way, you can also support more complicated constructs like this: template Repeat(int times, block inner_block) { for( int i=0; i<times; i++ ) inner_block; } Of course, the problem with this is that templates only allow for declarations, not arbitrary statements. Perhaps we could then add the following, which would mix a block into the instantiating scope: template Repeat(int times, block inner_block) { block Repeat { for( int i=0; i<times; i++ ) inner_block; } }
 Note the two blocks associated with a single template declaration. You
 might mix code around a third block with:

 void test()
 {
   mixin Trace!("test") {
     do_something();
     more_here();
   }
 }
Personally, I'd like to be able to drop the "mixin" keyword. I realise that semantically, it makes sense since you're mixing the contents of the template in, but without it, it just looks cooler :) void test() { Trace!("test") { do_something(); more_here(); } }
 resulting in the equivalent of:

 void test()
 {
   printf("Entering %s", f);
   do_something();
   more_here();
   printf("Exiting %s", f);
 }

 Ideally, such a construct could be used in conjunction with a
 conditional version statement:

 void test()
 {
   version (Log) mixin Trace!("test") {
     do_something();
     more_here();
   }
 }

 which when logging is disabled would evaluate to:

 void test()
 {
   do_something();
   more_here();
 }

 Is this feasible? Are there better ways?

 Matthias
I'll steal a Pythonism, and vote +1. This would be *really* handy, and it would allow for the creation of almost arbitrary control structures! For the longest time, I've had evil thoughts of making a D preprocessor that only operated on complete, valid parse trees. It would basically be a D compiler that read in D, modified it in some way, then spat it back out. With that, you could make structures like this: fori( int i; 10 ) block; Which would be "expanded" by the preprocessor as: for( int i=0; i<10; i++ ) block; But using the above idea, you could just write this as a template: template fori(alias variable, int limit, block inner) { block fori { for( variable = 0; variable < limit; variable++ ) inner; } } Of course, this would be helped if we could drop in arbitrary symbols or declarations, but I can live without that :) -- Daniel "Must... have... meta... programming..." Keep
I have proposed this before: http://www.digitalmars.com/d/archives/digitalmars/D/24770.html Shot down. :( -DavidM
May 04 2006
prev sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Matthias Spycher wrote:
 Here's an idea to extend mixins in a manner that would allow you to mix 
 code around a block in D.
 
 If you had:
 
 template Trace(f:char[])
 {
   printf("Entering %s", f);
 }
 {
   printf("Exiting %s", f);
 }
 
 Note the two blocks associated with a single template declaration. You 
 might mix code around a third block with:
<snip> A template in D is a collection of declarations. The idea of overloading them like this doesn't really make sense to me. Besides, I can imagine it being difficult to parse, possibly even ambiguous, if you have to worry about whether each template has one or two bodies. But the concept of reusable in/out blocks isn't a bad one. We could have it, but we should think a bit about the notation. Stewart. -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d- s:- C++ a->--- UB P+ L E W++ N+++ o K- w++ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++++ h-- r-- !y ------END GEEK CODE BLOCK------ My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
May 04 2006