www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Groovy

reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Groovy(http://groovy.codehaus.org/) is a dynamic language implemented on
the Java VM with strong Java integration. As Groovy's roots and
aims partially overlap with D's, some solutions might be interesting.

DISCLAIMER: I'm not a Groovy expert.

1) ranges

Groovy:
#
# assert (x in 2 .. 5);
#
# switch(y) {
#    case 1: break;
#    case 1900 .. 2006: break;
# }
#

current D:
#
# assert((2 <= x) && (x <= 5));
#
# switch(y) {
#    case 1: break;
#    default:
#       if((1900 <= y) && (y <= 2006)){
#          break;
#       }
# }

Especially the ranges support for switch/case is very useful.


2) literals for associative arrays

Groovy:
#
# def map = ['a': 1, 'b': 2, 'c': 3]
#

current D:
#
# int[char] map;
# map['a'] = 1;
# map['b'] = 2;
# map['c'] = 3;
#

Other useful features of Groovy depend too much on the VM
(e.g. dynamic extending of classes) for integration into D.

Thomas


-----BEGIN PGP SIGNATURE-----

iD8DBQFFmACaLK5blCcjpWoRAgKqAJ9BZIaQcCAux4EJn8ZHD4MyJdpn8QCfTb0N
iq1UGHbq25cNJCN8ZPv+RnY=
=IPRp
-----END PGP SIGNATURE-----
Dec 31 2006
next sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 Groovy(http://groovy.codehaus.org/) is a dynamic language implemented on
 the Java VM with strong Java integration. As Groovy's roots and
 aims partially overlap with D's, some solutions might be interesting.
 
 DISCLAIMER: I'm not a Groovy expert.
 
 1) ranges
 
 Groovy:
 #
 # assert (x in 2 .. 5);
 #
 # switch(y) {
 #    case 1: break;
 #    case 1900 .. 2006: break;
 # }
 #
 
 current D:
 #
 # assert((2 <= x) && (x <= 5));
 #
 # switch(y) {
 #    case 1: break;
 #    default:
 #       if((1900 <= y) && (y <= 2006)){
 #          break;
 #       }
 # }
 
 Especially the ranges support for switch/case is very useful.
 
 
 2) literals for associative arrays
 
 Groovy:
 #
 # def map = ['a': 1, 'b': 2, 'c': 3]
 #
 

'def' for auto type deduction. Nice. Again, I like it more than 'auto'. As for range types, and map literals, I wouldn't mind them in the language, but I've never felt much need for them , but that's likely just me. (in the code I've seen, I don't recall a place where it could be used, at least in non-temporary code)
 current D:
 #
 # int[char] map;
 # map['a'] = 1;
 # map['b'] = 2;
 # map['c'] = 3;
 #
 
 Other useful features of Groovy depend too much on the VM
 (e.g. dynamic extending of classes) for integration into D.
 
 Thomas
 
 
 -----BEGIN PGP SIGNATURE-----
 
 iD8DBQFFmACaLK5blCcjpWoRAgKqAJ9BZIaQcCAux4EJn8ZHD4MyJdpn8QCfTb0N
 iq1UGHbq25cNJCN8ZPv+RnY=
 =IPRp
 -----END PGP SIGNATURE-----

I just took a quick look under their site, but I've stumbled on something very interesting: ---- quote from: http://groovy.codehaus.org/Quick+Start ---- If no parameter(s) is(are) specified before -> symbol then a default named parameter, called 'it' can be used. e.g. def closure = { println "hello " + it } closure.call("world!") ---- I'm thinking if something like that can be used to ease idioms like: intArray.apply( (int e) { e++;} ); where the "(int e)" is mostly redundant. Such that it would be nice if the language could support a syntax like this: intArray.apply( { it++;} ); It could work in D in two ways, both with different semantics and advantages. One is like what I bet is the Groovy way (didn't look enough to confirm), where 'it' is a generic parameter (erased to Object in runtime, and primitives are boxed). But that doesn't fit well with D. Another way is to deduce the full delegate type from the context (somewhat like string literals), so that in the example above the delegate literal gets deduced to a "(int it) { it++;}" type. But that has some problems, like you can't do stuff like dg = { it++; }; because then you cannot deduce dg's type, so this behavior also seems sub-optimal. Anyways my point is this is an issue worthy of thinking about. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Dec 31 2006
prev sibling parent reply "bls" <killing__Zoe web.de> writes:
Hallo Thomas,
Just in case that you like Groovy, have a look at Suneido. www.suneido.com
which has a quit similar
language implemented. What I really like is the block construct as follows :
(Would be nice to have something like that in D. ) MfG Bjoern
Suneido supports Smalltalk style "blocks". Basically, a block is a section
of code within a function, that can be called like a function, but that
operates within the context of the function call that created it (i.e.
shares its local variables).

Blocks can be used to implement user defined "control constructs". (In
Smalltalk, all control constructs are implemented with blocks.) For example,
you could implement your own version of "foreach":

for_each = function (list, block)
{
for (i = 0; i < list.Size(); ++i)
block(list[i])
}
list = #(12, 34, 56)
for_each(list)
{ |x| Print(x) }
=>  12
34
56
Suneido treats a block immediately following a function call as an
additional argument.

Blocks can also be used to execute sections of code in specific "contexts".
For example, the Catch function traps exceptions and returns them. (This is
useful in unit tests to verify that expected exceptions occur.)

catcher = function (block)
{
try
return block()
catch (x)
return x
}
catcher( { xyz } ) => "unitialized variable: xyz"
But the interesting part is that a block can outlive the function call that
created it, and when it does so, it keeps its context (set of local
variables). For example:

make_counter = function (next)
{ return { next++ } }
counter = make_counter(10)
Print(counter())
Print(counter())
Print(counter())
=>  10
11
12
In this example, make_counter returns a block. The block returns next++. You
see this type of code in Lisp / Scheme.


"Thomas Kuehne" <thomas-dloop kuehne.cn> schreef in bericht
news:slrnepg04s.4v0.thomas-dloop birke.kuehne.cn...
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Groovy(http://groovy.codehaus.org/) is a dynamic language implemented on
 the Java VM with strong Java integration. As Groovy's roots and
 aims partially overlap with D's, some solutions might be interesting.

 DISCLAIMER: I'm not a Groovy expert.

 1) ranges

 Groovy:
 #
 # assert (x in 2 .. 5);
 #
 # switch(y) {
 #    case 1: break;
 #    case 1900 .. 2006: break;
 # }
 #

 current D:
 #
 # assert((2 <= x) && (x <= 5));
 #
 # switch(y) {
 #    case 1: break;
 #    default:
 #       if((1900 <= y) && (y <= 2006)){
 #          break;
 #       }
 # }

 Especially the ranges support for switch/case is very useful.


 2) literals for associative arrays

 Groovy:
 #
 # def map = ['a': 1, 'b': 2, 'c': 3]
 #

 current D:
 #
 # int[char] map;
 # map['a'] = 1;
 # map['b'] = 2;
 # map['c'] = 3;
 #

 Other useful features of Groovy depend too much on the VM
 (e.g. dynamic extending of classes) for integration into D.

 Thomas


 -----BEGIN PGP SIGNATURE-----

 iD8DBQFFmACaLK5blCcjpWoRAgKqAJ9BZIaQcCAux4EJn8ZHD4MyJdpn8QCfTb0N
 iq1UGHbq25cNJCN8ZPv+RnY=
 =IPRp
 -----END PGP SIGNATURE-----

Jan 01 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"bls" <killing__Zoe web.de> wrote in message 
news:enb0r2$51f$1 digitaldaemon.com...

 Suneido supports Smalltalk style "blocks". Basically, a block is a section
 of code within a function, that can be called like a function, but that
 operates within the context of the function call that created it (i.e.
 shares its local variables).

Nested functions and delegate literals in D do (almost, see below) the same thing. Access to outer locals is a very useful feature indeed.
 Blocks can be used to implement user defined "control constructs". (In
 Smalltalk, all control constructs are implemented with blocks.) For 
 example,
 you could implement your own version of "foreach":

 for_each = function (list, block)
 {
 for (i = 0; i < list.Size(); ++i)
 block(list[i])
 }
 list = #(12, 34, 56)
 for_each(list)
 { |x| Print(x) }
 =>  12
 34
 56

What's funny about this example is that this is _precisely_ how D handles iteration with foreach, except that it's hidden behind loop-like syntax. The body of a foreach loop is converted into a nested function and passed as a callback to the opApply for the given container.
 Suneido treats a block immediately following a function call as an
 additional argument.

This is a really cool idea that some people (myself included) would like to see in D. The closest thing we have now is: for_each(list, (x) { writefln(x); });
 Blocks can also be used to execute sections of code in specific 
 "contexts".
 For example, the Catch function traps exceptions and returns them. (This 
 is
 useful in unit tests to verify that expected exceptions occur.)

 catcher = function (block)
 {
 try
 return block()
 catch (x)
 return x
 }
 catcher( { xyz } ) => "unitialized variable: xyz"

Exception catcher(void delegate() dg) { try { dg(); } catch(Exception e) { return e; } return null; } ... Exception e = catcher ({ someCode(); });
 But the interesting part is that a block can outlive the function call 
 that
 created it, and when it does so, it keeps its context (set of local
 variables). For example:

 make_counter = function (next)
 { return { next++ } }
 counter = make_counter(10)
 Print(counter())
 Print(counter())
 Print(counter())
 =>  10
 11
 12
 In this example, make_counter returns a block. The block returns next++. 
 You
 see this type of code in Lisp / Scheme.

This is called a static closure, and is something D's nested functions don't do. The workaround involves manually creating a context using a struct or something, and returning a bound delegate using an instance of that aggregate allocated with new: int delegate() makeCounter(int next) { struct Context { int next; int func() { return next++; } } Context* ctx = new Context; ctx.next = next; return &ctx.func; } ... auto counter = makeCounter(10); writefln(counter()); writefln(counter()); writefln(counter()); This is basically what Suneido is doing for you behind the scenes. It seems like a relatively simple feature to implement, but there are many issues to consider. One, when do you allocate the context for the delegate? When it leaves the function? How do you know that it isn't assigned to somewhere else and not returned? So you allocate it when it's declared, but then you lose the ability to access the outer function's copy of the locals, and you also lose performance if the delegate never needs to be returned, so you're allocating an unnecessary context with every call to the outer function. Then there's the problem of nested functions in nested functions accessing local variables from more than one level of nesting... etc. etc. etc. Please don't take this post to mean that I'm shooting down your ideas! I'm just trying to show some of the features of D which are something like what you've demonstrated.
Jan 01 2007
next sibling parent "bls" <killing__Zoe web.de> writes:
Thanks Jarret, very interesting stuff and comments.!
Happy new year,
Bjoern
 Please don't take this post to mean that I'm shooting down your ideas!

 just trying to show some of the features of D which are something like

 you've demonstrated.

Jan 01 2007
prev sibling next sibling parent "Andrey Khropov" <andkhropov_nosp m_mtu-net.ru> writes:
Jarrett Billingsley wrote:

The closest thing we have now is:
 
 for_each(list, (x)
 {
    writefln(x);
 });

Unfortunately type inference for delegate parameters isn't supported yet :(. So we have to specify its type: for_each(list, (int x) { writefln(x); });
 This is basically what Suneido is doing for you behind the scenes.  It seems
 like a relatively simple feature to implement, but there are many issues to
 consider.  One, when do you allocate the context for the delegate?  When it
 leaves the function?  How do you know that it isn't assigned to somewhere
 else and not returned?  So you allocate it when it's declared, but then you
 lose the ability to access the outer function's copy of the locals, and you
 also lose performance if the delegate never needs to be returned, so you're
 allocating an unnecessary context with every call to the outer function. Then
 there's the problem of nested functions in nested functions accessing local
 variables from more than one level of nesting... etc. etc. etc.

There are a plenty of functional programming language compilers that successfully deal with these problems. -- AKhropov
Jan 01 2007
prev sibling next sibling parent David Medlock <noone nowhere.com> writes:
Jarrett Billingsley wrote:
 "bls" <killing__Zoe web.de> wrote in message 
 news:enb0r2$51f$1 digitaldaemon.com...
 
 
Suneido supports Smalltalk style "blocks". Basically, a block is a section
of code within a function, that can be called like a function, but that
operates within the context of the function call that created it (i.e.
shares its local variables).

Nested functions and delegate literals in D do (almost, see below) the same thing. Access to outer locals is a very useful feature indeed.
Blocks can be used to implement user defined "control constructs". (In
Smalltalk, all control constructs are implemented with blocks.) For 
example,
you could implement your own version of "foreach":

for_each = function (list, block)
{
for (i = 0; i < list.Size(); ++i)
block(list[i])
}
list = #(12, 34, 56)
for_each(list)
{ |x| Print(x) }
=>  12
34
56

What's funny about this example is that this is _precisely_ how D handles iteration with foreach, except that it's hidden behind loop-like syntax. The body of a foreach loop is converted into a nested function and passed as a callback to the opApply for the given container.
Suneido treats a block immediately following a function call as an
additional argument.

This is a really cool idea that some people (myself included) would like to see in D. The closest thing we have now is: for_each(list, (x) { writefln(x); });
Blocks can also be used to execute sections of code in specific 
"contexts".
For example, the Catch function traps exceptions and returns them. (This 
is
useful in unit tests to verify that expected exceptions occur.)

catcher = function (block)
{
try
return block()
catch (x)
return x
}
catcher( { xyz } ) => "unitialized variable: xyz"


Hehe. Deja Vu Jarrett(times 2 I think): http://www.digitalmars.com/d/archives/digitalmars/D/24770.html I do think that lazy expressions get us 80 or 90 percent of the way there in most cases, though. -DavidM
Jan 02 2007
prev sibling parent janderson <askme me.com> writes:
Jarrett Billingsley wrote:
 "bls" <killing__Zoe web.de> wrote in message 
 news:enb0r2$51f$1 digitaldaemon.com...

 Suneido treats a block immediately following a function call as an
 additional argument.


This is really cool. I would really like to see this in D. I'd imagine that it could make it into the template syntax somehow. -Joel
Jan 03 2007