www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Groovy Templates for D?

reply David Medlock <noone nowhere.com> writes:
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 30 2005
parent reply "Walter" <newshound digitalmars.com> writes:
I think D can do what you're asking with function literals and delegate
literals.
May 30 2005
next sibling parent David Medlock <noone nowhere.com> writes:
Walter wrote:
 I think D can do what you're asking with function literals and delegate
 literals.
 
 

May 31 2005
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
parent reply David Medlock <noone nowhere.com> writes:
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.

appearing after a template it would seem a nice bit of syntactical convenience. -DavidM
May 31 2005
next sibling parent Georg Wrede <georg.wrede nospam.org> writes:
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.

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.
Jun 01 2005
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
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.

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
Jun 01 2005
next sibling parent reply David Medlock <noone nowhere.com> writes:
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

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
Jun 01 2005
parent David Medlock <noone nowhere.com> writes:
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

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
Jun 01 2005
prev sibling parent Sean Kelly <sean f4.ca> writes:
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
Jun 01 2005