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
file = new File("c:/dynamic.ini"); file.eachLine{ println(it) }
Very elegant and easy on the old eyes.
Java
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
Iteration.eachLine("c:/dynamic.ini", new LineHandler() { public void handleLine(String line) { System.out.println(line); } });
and the supporting code :
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...
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
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
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
#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
// 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; });






