digitalmars.D - Groovy
- Thomas Kuehne (48/48) Dec 31 2006 -----BEGIN PGP SIGNED MESSAGE-----
- Bruno Medeiros (35/98) Dec 31 2006 'def' for auto type deduction. Nice. Again, I like it more than 'auto'.
- bls (52/100) Jan 01 2007 Hallo Thomas,
- Jarrett Billingsley (67/117) Jan 01 2007 Nested functions and delegate literals in D do (almost, see below) the s...
- bls (6/9) Jan 01 2007 Thanks Jarret, very interesting stuff and comments.!
- Andrey Khropov (11/27) Jan 01 2007 Unfortunately type inference for delegate parameters isn't supported yet...
- David Medlock (7/74) Jan 02 2007 Hehe.
- janderson (4/8) Jan 03 2007 This is really cool. I would really like to see this in D. I'd imagine...
-----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: current D: Especially the ranges support for switch/case is very useful. 2) literals for associative arrays Groovy: current D: 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
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: current D: Especially the ranges support for switch/case is very useful. 2) literals for associative arrays Groovy:'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: 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
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]) } 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: current D: Especially the ranges support for switch/case is very useful. 2) literals for associative arrays Groovy: current D: 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
"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]) } for_each(list) { |x| Print(x) } => 12 34 56What'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
Thanks Jarret, very interesting stuff and comments.! Happy new year, BjoernPlease don't take this post to mean that I'm shooting down your ideas!I'mjust trying to show some of the features of D which are something likewhatyou've demonstrated.No prob. Good points
Jan 01 2007
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
Jarrett Billingsley wrote:"bls" <killing__Zoe web.de> wrote in message news:enb0r2$51f$1 digitaldaemon.com...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. -DavidMSuneido 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]) } for_each(list) { |x| Print(x) } => 12 34 56What'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"
Jan 02 2007
Jarrett Billingsley wrote:"bls" <killing__Zoe web.de> wrote in message news:enb0r2$51f$1 digitaldaemon.com...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. -JoelSuneido treats a block immediately following a function call as an additional argument.
Jan 03 2007