One aspect of Groovy ( and Ruby, Python , etc ) I really like is the combination of closures and support for them in the Groovy DK .
As an example, consider iterating through every line in a text file :
Groovy
| Code Block |
|---|
file = new File("c:/dynamic.ini");
file.eachLine{
println(it)
}
|
Very elegant and easy on the old eyes.
Java
| Code Block |
|---|
BufferedReader input = null;
try {
input = new BufferedReader (new FileReader("c:/dynamic.ini"));
String line;
while ((line = input.readLine()) != null) {
System.out.println(line);
}
} finally {
if(input != null){
input.close();
}
}
|
Oh dear.
Java with some help
| Code Block |
|---|
Iteration.eachLine("c:/dynamic.ini", new LineHandler() {
public void handleLine(String line) {
System.out.println(line);
}
});
|
and the supporting code :
| Code Block |
|---|
public static void eachLine(String path, LineHandler handler) throws IOException {
FileReader file = null;
try {
file = new FileReader(path); // Open the file.
BufferedReader input = new BufferedReader(file);
String line;
while ((line = input.readLine()) != null) {
handler.handleLine(line);
}
} finally {
if (file != null) {
file.close();
}
}
}
|
C#
Apologies for my C#, I have not been writing it for very long...
| Code Block |
|---|
string line;
using (StreamReader reader = File.OpenText(@"c:\dynamic.ini")) {
while((line = reader.ReadLine()) != null){
Console.WriteLine(line);
}
}
|
No need to escape path string is nice
C# 2.0 with some help
With C# 2.0 and the 2.0 .NET framework the addition of anonymous delegates we can produce a very concise and readable solution
| Code Block |
|---|
Iterators.EachLine(@"c:\dynamic.ini", delegate(string it) {
Console.WriteLine(it);
});
|
similar in elegance to the Groovy one.
This depends on the following utility class
| Code Block |
|---|
public static class Iterators {
public delegate void Closure<T>(T it);
public static void EachLine(string path, Closure<string> closure) {
string line = null;
using (StreamReader reader = File.OpenText(path)) {
line = reader.ReadLine();
while (line != null) {
closure(line);
line = reader.ReadLine();
}
}
}
}
|
Groovinating C#
You will notice that I have started implementing the Groovy DK set of collection iterators (each, findAll, find , etc ) for C# 2.0.
I do wish Microsoft and Sun would have built this kind of simplicity in....
There are 2 possible approaches to the Collections :
- Subclass and add the grooviness
- Add the grooviness as a set statci methods you plass the collection to
Here is some perlimenary code and tests of both types.
This subclasses List<T> and adds the groovination, and offers the same support ina static class
C# 2.0 Code
| Code Block |
|---|
#region Using directives
using System;
using System.Collections.Generic;
using System.IO;
#endregion
namespace Groovinator {
#region Delegatros
public class Delegatros {
public delegate void Closure<T>(T it);
public delegate T Functor<T>(T it);
public delegate bool Predicate<T>(T it);
}
#endregion
#region Collection Iterators
public class List<T> : System.Collections.Generic.List<T> {
public void Each(Delegatros.Closure<T> closure) {
foreach (T it in this) {
closure(it);
}
}
public List<T> FindAll(Delegatros.Predicate<T> predicate) {
//this is a bit poor
List<T> result = new List<T>();
foreach (T it in this) {
if (predicate(it)) {
result.Add(it);
}
}
return result;
}
public T Find(Delegatros.Predicate<T> predicate) {
foreach (T it in this) {
if (predicate(it)) {
return it;
}
}
return default(T);
}
public void Map(Delegatros.Functor<T> functor) {
List<T> result = new List<T>();
for(int i = 0;i< this.Count;++i){
this[i] = functor(this[i]);
}
}
}
public static class Iterators {
// Collections
public static void Each<T>(IEnumerable<T> enumerable, Delegatros.Closure<T> closure) {
foreach (T it in enumerable) {
closure(it);
}
}
public static List<T> FindAll<T>(IEnumerable<T> enumerable, Delegatros.Predicate<T> predicate) {
//this is a bit poor
List<T> result = new List<T>();
foreach (T it in enumerable) {
if (predicate(it)) {
result.Add(it);
}
}
return result;
}
public static T Find<T>(IEnumerable<T> enumerable, Delegatros.Predicate<T> predicate) {
foreach (T it in enumerable) {
if (predicate(it)) {
return it;
}
}
return default(T);
}
public static List<T> Map<T>(IEnumerable<T> enumerable, Delegatros.Functor<T> functor) {
List<T> result = new List<T>();
foreach (T it in enumerable) {
result.Add(functor(it));
}
return result;
}
}
#endregion
#region File Iterators
public static class IOIterators{
// File related iterators
public static void EachLine(string path, Delegatros.Closure<string> closure) {
string line = null;
using (StreamReader reader = File.OpenText(path)) {
line = reader.ReadLine();
while (line != null) {
closure(line);
line = reader.ReadLine();
}
}
}
}
#endregion
}
|
Some Usage Examples
| Code Block |
|---|
// open, print all lines of a text file , close
IOIterators.EachLine(@"c:\dynamic.ini", delegate(string it) {
Console.WriteLine(it);
});
List<string> list = new List<string>();
// populate list
// print a list of string
list.Each(delegate(string it) {
Console.WriteLine(it);
});
System.Collections.Generic.IEnumerable<string> res;
// find all items matching the predicate item.Contaons("8")
res = list.FindAll(delegate(string it) {
return it.Contains("8");
});
// find the first item where Item.Equals("10")
string ten = list.Find(delegate(string it) {
return it.Equals("10");
});
List<int> nums = new List<int>();
for (int j = 1; j < 11; ++j) {
nums.Add(j);
}
// apply a functor ( multiply by 2 ) to a list of ints
nums.Map(delegate(int num) {
return num * 2;
});
|