Thread overview
mixin extension
May 03, 2006
Matthias Spycher
May 04, 2006
Daniel Keep
May 04, 2006
Hasan Aljudy
May 04, 2006
Matthias Spycher
May 05, 2006
David Medlock
May 04, 2006
Stewart Gordon
May 03, 2006
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 04, 2006
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 04, 2006
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 04, 2006
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
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 05, 2006
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