Thread overview
Groovy Templates for D?
May 30, 2005
David Medlock
May 31, 2005
Walter
May 31, 2005
David Medlock
May 31, 2005
David Medlock
Jun 01, 2005
Georg Wrede
Jun 01, 2005
Sean Kelly
Jun 01, 2005
David Medlock
Jun 01, 2005
David Medlock
Jun 01, 2005
Sean Kelly
May 30, 2005
I program web/Oracle apps in Java for $$ and therefore attempt to make the situation as good(programming-power wise) as I can.

I recently dumped both velocity(a templating engine) and Struts(a Web framework) for the recently Sun-standardized Groovy language.

(the point is coming, keep reading)

It is quite frankly the most powerful language I've used yet for the JVM.  The implementation has a few dark corners but it has excellent power-to-usability.

The *best* feature I have found so far is how the language can be expanded using Java classes.  Basically any function call can include an attached body of code which is called a Closure(very close to a D delegate) as the last argument.  This is incredible expandibility.

For instance suppose I want to be able to do the following:

for(10) { print( "Hello" ); }

then I would use the following Java function.

void for( int n, Closure cl ) { while( n>0 ) { cl(); n--; } }

For Html its even better:

void form( Closure cl ) { write("<form>"); cl(); write("</form>"); }

then in script:

form() {
  out.write( "<input...");
}

I am wondering if this is feasible for D.  It would expand by orders of magnitude the language and make C-macros seem pretty silly(combined with the version system).

Syntax I would propose:

template Foo( alias int n, body f )
{
  void Foo() { while ( n>0 ) { n--; f(); } }
}

Foo!(100) { writefln("Hello World"); }

Perhaps this wouldnt add a ton, but....thoughts?

-DavidM
May 31, 2005
I think D can do what you're asking with function literals and delegate literals.


May 31, 2005
Walter wrote:
> I think D can do what you're asking with function literals and delegate
> literals.
> 
> 
ok :)
May 31, 2005
"Walter" <newshound@digitalmars.com> wrote in message news:d7gp1s$msm$1@digitaldaemon.com...
>I think D can do what you're asking with function literals and delegate
> literals.

I think what he's asking is that for a function such as:

void fork(int x, int y, void delegate() dg)
{
    writefln(x);
    writefln(y);
    dg();
}

If you were to use the function like so:

fork(5,10)
{
    writefln("delegate!");
}

It would implicitly be converted to

fork(5,10,void delegate() { writefln("delegate!"); });

The key being the implicit conversion of the immediately-following block of code into the last parameter.  A minor feature, and probably would have very limited usefulness, but it's interesting nonetheless.


May 31, 2005
Jarrett Billingsley wrote:

> "Walter" <newshound@digitalmars.com> wrote in message news:d7gp1s$msm$1@digitaldaemon.com...
> 
>>I think D can do what you're asking with function literals and delegate
>>literals.
> 
> 
> I think what he's asking is that for a function such as:
> 
> void fork(int x, int y, void delegate() dg)
> {
>     writefln(x);
>     writefln(y);
>     dg();
> }
> 
> If you were to use the function like so:
> 
> fork(5,10)
> {
>     writefln("delegate!");
> }
> 
> It would implicitly be converted to
> 
> fork(5,10,void delegate() { writefln("delegate!"); });
> 
> The key being the implicit conversion of the immediately-following block of code into the last parameter.  A minor feature, and probably would have very limited usefulness, but it's interesting nonetheless. 
> 
> 
Exactly.  Since I cannot think of an ambiguity with a code block appearing after a template it would seem a nice bit of syntactical convenience.

-DavidM
June 01, 2005
David Medlock wrote:
> Jarrett Billingsley wrote:
> 
>> "Walter" <newshound@digitalmars.com> wrote in message news:d7gp1s$msm$1@digitaldaemon.com...
>>
>>> I think D can do what you're asking with function literals and delegate
>>> literals.
>>
>> I think what he's asking is that for a function such as:
>>
>> void fork(int x, int y, void delegate() dg)
>> {
>>     writefln(x);
>>     writefln(y);
>>     dg();
>> }
>>
>> If you were to use the function like so:
>>
>> fork(5,10)
>> {
>>     writefln("delegate!");
>> }
>>
>> It would implicitly be converted to
>>
>> fork(5,10,void delegate() { writefln("delegate!"); });
>>
>> The key being the implicit conversion of the immediately-following block of code into the last parameter.  A minor feature, and probably would have very limited usefulness, but it's interesting nonetheless.
>>
> Exactly.  Since I cannot think of an ambiguity with a code block appearing after a template it would seem a nice bit of syntactical convenience.

This is yet another example of language constructs that are useful and powerful, but which may be used only by advanced programmers. Implementing this kind of stuff ends up cluttering the syntax space, as well as bloating the compiler, because each of these (admittedly good) features would be implemented more or less separately. That tends to create interdependencies and barriers in

 - compiler source
 - language semantics
 - language syntax

The Metalanguage (search for my posts in d.D around Feb/March) would take care of this kind of issues. (Among other things.)

Instead of implementing quite a few things directly in the compiler, or the language itself, we would be better off having a mechanism with which this and other things could be created by the programmer as the need arises.

I'm actually working on this since some time, but don't expect any real results before Q4.

----

Currently I'm not as free to do D stuff as I was earlier this year, but I'm still at it, in the background.
June 01, 2005
In article <d7itg7$44m$1@digitaldaemon.com>, David Medlock says...
>
>Jarrett Billingsley wrote:
>
>> "Walter" <newshound@digitalmars.com> wrote in message news:d7gp1s$msm$1@digitaldaemon.com...
>> 
>>>I think D can do what you're asking with function literals and delegate literals.
>> 
>> 
>> I think what he's asking is that for a function such as:
>> 
>> void fork(int x, int y, void delegate() dg)
>> {
>>     writefln(x);
>>     writefln(y);
>>     dg();
>> }
>> 
>> If you were to use the function like so:
>> 
>> fork(5,10)
>> {
>>     writefln("delegate!");
>> }
>> 
>> It would implicitly be converted to
>> 
>> fork(5,10,void delegate() { writefln("delegate!"); });
>> 
>> The key being the implicit conversion of the immediately-following block of code into the last parameter.  A minor feature, and probably would have very limited usefulness, but it's interesting nonetheless.
>> 
>> 
>Exactly.  Since I cannot think of an ambiguity with a code block appearing after a template it would seem a nice bit of syntactical convenience.

void func( int a, float b );
void func( int a, float b, void delegate() );

func( 1, 1.0 )
{

}

Which function gets called by the above?  Also, how would:

// accepts a delegate with parameters
void func( int a, float b, void delegate( int c ) );

be represented using the above method?  I grant it's a cool idea, but the solution to both of these issues isn't obvious to me.


Sean


June 01, 2005
Sean Kelly wrote:
> In article <d7itg7$44m$1@digitaldaemon.com>, David Medlock says...
> 
>>Jarrett Billingsley wrote:
>>
>>
>>>"Walter" <newshound@digitalmars.com> wrote in message news:d7gp1s$msm$1@digitaldaemon.com...
>>>
>>>
>>>>I think D can do what you're asking with function literals and delegate
>>>>literals.
>>>
>>>
>>>I think what he's asking is that for a function such as:
>>>
>>>void fork(int x, int y, void delegate() dg)
>>>{
>>>    writefln(x);
>>>    writefln(y);
>>>    dg();
>>>}
>>>
>>>If you were to use the function like so:
>>>
>>>fork(5,10)
>>>{
>>>    writefln("delegate!");
>>>}
>>>
>>>It would implicitly be converted to
>>>
>>>fork(5,10,void delegate() { writefln("delegate!"); });
>>>
>>>The key being the implicit conversion of the immediately-following block of code into the last parameter.  A minor feature, and probably would have very limited usefulness, but it's interesting nonetheless. 
>>>
>>>
>>
>>Exactly.  Since I cannot think of an ambiguity with a code block appearing after a template it would seem a nice bit of syntactical convenience.
> 
> 
> void func( int a, float b );
> void func( int a, float b, void delegate() );
> 
> func( 1, 1.0 )
> {
> 
> }
> 
> Which function gets called by the above?  Also, how would:
> 
> // accepts a delegate with parameters
> void func( int a, float b, void delegate( int c ) );
> 
> be represented using the above method?  I grant it's a cool idea, but the
> solution to both of these issues isn't obvious to me.
> 
> 
> Sean
> 
> 
I was advocating this only for templates with an explicit delegate as the last parameter, like my Java examples.  So you would need:

func!( 1, 10 ) { ... }

there is still nothing stopping you from calling:

func!( 1, 10, delegate { ... } );

For the parameters, I admit I don't have a solution.
In Groovy you can specify:

myfunction = { a, b -> print(a); print(b); ... }
...
myfunction( 100, 200 )


In response to George, I disagree it is syntactical clutter.

There are 3 basic uses for templates and macros in general:

1. Generation of type dependent meta-types (aka specialized classes).
2. Generation of type dependent functions  (polymorphic behavior dispatched on type, rather than value)
3. _Execution_ of code dispatched on passed types or values.

#3 is the speciality of C-macros and allows various powerful(but dangerous!) abilities.  Usually by introducing a new block which allows local variables, etc.

I believe this syntactical addition would close the gap between what C-macros can do and do it in a safer way.

This is not to say your Metalanguage would not, just disagree with the 'clutter' statement.

Its not a huge deal, but this type of thing is quite useful in Groovy.
-DavidM


June 01, 2005
In article <d7kg95$1pqa$1@digitaldaemon.com>, Sean Kelly says...
>
>Also, how would:
>
>// accepts a delegate with parameters
>void func( int a, float b, void delegate( int c ) );
>
>be represented using the above method?

Scratch this.  Anonymous delegates obviously don't take parameters :p


Sean


June 01, 2005
David Medlock wrote:
> Sean Kelly wrote:
> 
>> In article <d7itg7$44m$1@digitaldaemon.com>, David Medlock says...
>>
>>> Jarrett Billingsley wrote:
>>>
>>>
>>>> "Walter" <newshound@digitalmars.com> wrote in message news:d7gp1s$msm$1@digitaldaemon.com...
>>>>
>>>>
>>>>> I think D can do what you're asking with function literals and delegate
>>>>> literals.
>>>>
>>>>
>>>>
>>>> I think what he's asking is that for a function such as:
>>>>
>>>> void fork(int x, int y, void delegate() dg)
>>>> {
>>>>    writefln(x);
>>>>    writefln(y);
>>>>    dg();
>>>> }
>>>>
>>>> If you were to use the function like so:
>>>>
>>>> fork(5,10)
>>>> {
>>>>    writefln("delegate!");
>>>> }
>>>>
>>>> It would implicitly be converted to
>>>>
>>>> fork(5,10,void delegate() { writefln("delegate!"); });
>>>>
>>>> The key being the implicit conversion of the immediately-following block of code into the last parameter.  A minor feature, and probably would have very limited usefulness, but it's interesting nonetheless.
>>>>
>>>
>>> Exactly.  Since I cannot think of an ambiguity with a code block appearing after a template it would seem a nice bit of syntactical convenience.
>>
>>
>>
>> void func( int a, float b );
>> void func( int a, float b, void delegate() );
>>
>> func( 1, 1.0 )
>> {
>>
>> }
>>
>> Which function gets called by the above?  Also, how would:
>>
>> // accepts a delegate with parameters
>> void func( int a, float b, void delegate( int c ) );
>>
>> be represented using the above method?  I grant it's a cool idea, but the
>> solution to both of these issues isn't obvious to me.
>>
>>
>> Sean
>>
>>
> I was advocating this only for templates with an explicit delegate as the last parameter, like my Java examples.  So you would need:
> 
> func!( 1, 10 ) { ... }
> 
> there is still nothing stopping you from calling:
> 
> func!( 1, 10, delegate { ... } );
> 
> For the parameters, I admit I don't have a solution.
> In Groovy you can specify:
> 
> myfunction = { a, b -> print(a); print(b); ... }
> ...
> myfunction( 100, 200 )
> 
> 
> In response to George, I disagree it is syntactical clutter.
> 
> There are 3 basic uses for templates and macros in general:
> 
> 1. Generation of type dependent meta-types (aka specialized classes).
> 2. Generation of type dependent functions  (polymorphic behavior dispatched on type, rather than value)
> 3. _Execution_ of code dispatched on passed types or values.
> 
> #3 is the speciality of C-macros and allows various powerful(but dangerous!) abilities.  Usually by introducing a new block which allows local variables, etc.
> 
> I believe this syntactical addition would close the gap between what C-macros can do and do it in a safer way.
> 
> This is not to say your Metalanguage would not, just disagree with the 'clutter' statement.
> 
> Its not a huge deal, but this type of thing is quite useful in Groovy.
> -DavidM
> 
> 

As a quick follow up, I think that if this syntactical change were implemented (kinks worked out), it would make foreach/opApply implementable in Phobos as a template specializing on Object or array types!

foreach!( int item, int[] array ) { ... }

-DavidM