---- C# 2.0 (a.k.a Whidbey) now supports anonymous methods (blocks) and Icon-style iterators. Anonymous methods allow you to return a closure from another method (a la Smalltalk blocks, Ruby blocks, Lisp lambda's, etc.): delegate T Function(); // boilerplate static decl of signature Function counterFrom( int n ) { return delegate { return n++; }; // parens aren't needed unless there's an argument passed to the anonymous method. } Function counter = counterFrom( 3 ); Console.Write''''''Line(counter()); >>> 3 Console.Write''''''Line(counter()); >>> 4 Console.Write''''''Line(counter()); >>> 5 Iterators allow you to "push" a sequence of values into a consumer that iterates using the foreach language construct (similar to Ruby's each method): IEnumerable counterFrom( int n ) { while (true) yield return n++; } foreach (int n in counterFrom(3)) { if (n > 5) break; Console.Write''''''Line(n) } >>> 3 >>> 4 >>> 5 ---- This is a CSharp version of RobertDiFalco''''''s excellent page BlocksInJava, having loved this page for a while and being envious of Smalltalk for some time, I finally got around to translating it to CSharp, since I can't have anonymous delegates until 2005. See BlocksInJava for an explanation of how to use this. CSharp doesn't have anonymous inners, so the Block class isn't used, but this can be used for expression composition rather than specialization. RamonLeon public interface Predicate { bool Is(); } public interface Unary''''''Predicate { bool Is(object anArg); } public interface Binary''''''Predicate { bool Is(object firstArg, object secondArg); } public interface Function { object Eval(); } public interface Unary''''''Function { object Eval(object anArg); } public interface Binary''''''Function { object Eval(object firstArg, object secondArg); } public interface Procedure { void Run(); } public interface Unary''''''Procedure { void Run(object anArg); } public interface Binary''''''Procedure { void Run(object firstArg, object secondArg); } public class And:Binary''''''Predicate { public bool Is(object firstArg, object secondArg) { return (bool)firstArg&&(bool)secondArg; } } public class Or:Binary''''''Predicate { public bool Is(object firstArg, object secondArg) { return (bool)firstArg||(bool)secondArg; } } public class Equals:Binary''''''Predicate { public bool Is(object firstArg, object secondArg) { return firstArg.Equals(secondArg); } } public class Same:Binary''''''Predicate { public bool Is(object firstArg, object secondArg) { return (bool)firstArg==(bool)secondArg; } } public class Less:Binary''''''Predicate { public bool Is(object firstArg, object secondArg) { return ((IComparable)firstArg).Compare''''''To(secondArg)<0; } } public class Greater:Binary''''''Predicate { public bool Is(object firstArg, object secondArg) { return ((IComparable)firstArg).Compare''''''To(secondArg)>0; } } public class Not:Unary''''''Predicate { public bool Is(object firstArg) { return !(bool)firstArg; } } public class Binary''''''Compose:Unary''''''Predicate { Binary''''''Predicate anOperator; Unary''''''Predicate firstArg; Unary''''''Predicate secondArg; public Binary''''''Compose(Binary''''''Predicate anOperator, Unary''''''Predicate firstArg, Unary''''''Predicate secondArg) { this.anOperator = anOperator; this.firstArg = firstArg; this.secondArg = secondArg; } public bool Is(object anArg) { return anOperator.Is(firstArg.Is(anArg),secondArg.Is(anArg)); } public static Binary''''''Compose And(Unary''''''Predicate firstArg, Unary''''''Predicate secondArg) { return new Binary''''''Compose(new And(), firstArg, secondArg); } public static Binary''''''Compose Or(Unary''''''Predicate firstArg, Unary''''''Predicate secondArg) { return new Binary''''''Compose(new Or(), firstArg, secondArg); } } public class Unary''''''Compose:Unary''''''Predicate { Unary''''''Predicate firstPredicate; Unary''''''Predicate secondPredicate; public Unary''''''Compose(Unary''''''Predicate firstPredicate, Unary''''''Predicate secondPredicate) { this.firstPredicate = firstPredicate; this.secondPredicate = secondPredicate; } public bool Is(object anArg) { return firstPredicate.Is(secondPredicate.Is(anArg)); } public static Unary''''''Compose Not(Unary''''''Predicate aPredicate) { return new Unary''''''Compose(new Not(),aPredicate); } } public abstract class Abstract''''''Binder:Unary''''''Predicate { Binary''''''Predicate thePredicate; object theBoundArg; public bool Is''''''Bound() { return theBoundArg != null; } public abstract bool Is(object anArg); public void Bind(object anArg) { theBoundArg = anArg; } public void Adapt(Binary''''''Predicate aPredicate) { thePredicate = aPredicate; } protected bool Do''''''Is''''''As''''''First(object anArg) { return thePredicate.Is(anArg, theBoundArg); } protected bool Do''''''Is''''''As''''''Second(object anArg) { return thePredicate.Is(theBoundArg, anArg); } } public class Binder''''''First:Abstract''''''Binder { public Binder''''''First(Binary''''''Predicate aPredicate):this(aPredicate,null) {} public Binder''''''First(Binary''''''Predicate aPredicate, object anArg) { Adapt(aPredicate); Bind(anArg); } public override bool Is(object anArg) { return Do''''''Is''''''As''''''Second(anArg); } } public class Binder''''''Second:Abstract''''''Binder { public Binder''''''Second(Binary''''''Predicate aPredicate):this(aPredicate, null) {} public Binder''''''Second(Binary''''''Predicate aPredicate, object anArg) { Adapt(aPredicate); Bind(anArg); } public override bool Is(object anArg) { return Do''''''Is''''''As''''''First(anArg); } } /// /// Higher Order function's with the new microsoft style naming convention that /// will be used in C sharp 2.0. These are done STL style so that all algorithms /// work on enumerators... these methods should work with any container. /// public class Iterate { public static object Get''''''First(IEnumerable aList) { foreach(object anObject in aList) return anObject; return null; } public static object Get''''''Second(IEnumerable aList) { return Get''''''First(Get''''''Rest(aList)); } public static object Get''''''Third(IEnumerable aList) { return Get''''''First(Get''''''Rest(Get''''''Rest(aList))); } public static object Get''''''Fourth(IEnumerable aList) { return Get''''''First(Get''''''Rest(Get''''''Rest(Get''''''Rest(aList)))); } public static object Get''''''Fifth(IEnumerable aList) { return Get''''''First(Get''''''Rest(Get''''''Rest(Get''''''Rest(Get''''''Rest(aList))))); } public static IList Get''''''Rest(IEnumerable aList) { IList result = Merge(aList,new Array''''''List()); result.Remove(Get''''''First(aList)); return result; } public static IList Merge(IEnumerable aList, IList anotherList) { foreach(object anObject in aList) anotherList.Add(anObject); return anotherList; } public static IList Find''''''All(IEnumerable aList, Unary''''''Predicate match) { Array''''''List result = new Array''''''List(); foreach(object anObject in aList) if(match.Is(anObject)) result.Add(anObject); return result; } public static IList Find''''''All''''''Not(IEnumerable aList, Unary''''''Predicate match) { Array''''''List result = new Array''''''List(); foreach(object anObject in aList) if(!match.Is(anObject)) result.Add(anObject); return result; } public static object Find(IEnumerable aList, Unary''''''Predicate match) { foreach(object anObject in aList) if(match.Is(anObject)) return anObject; return null; } public static object Find''''''Last(IEnumerable aList, Unary''''''Predicate match) { foreach(object anObject in Reverse(aList)) if(match.Is(anObject)) return anObject; return null; } public static object Inject(IEnumerable aList, object aValue, Binary''''''Function aBlock) { foreach(object anObject in aList) aValue = aBlock.Eval(aValue,anObject); return aValue; } public static bool Exists(IEnumerable aList, Unary''''''Predicate match) { foreach(object anObject in aList) if(match.Is(anObject)) return true; return false; } public static bool True''''''For''''''All(IEnumerable aList, Unary''''''Predicate match) { foreach(object anObject in aList) if(!match.Is(anObject)) return false; return true; } public static void Remove''''''All(IList aList, Unary''''''Predicate match) { IList toRemove = Find''''''All(aList, match); foreach(object anObject in toRemove) aList.Remove(anObject); } public static void For''''''Each(IEnumerable aList, Unary''''''Procedure toRun) { foreach(object anObject in aList) toRun.Run(anObject); } public static void For''''''Each''''''Child(Control aControl, Unary''''''Procedure aProc) { aProc.Run(aControl); foreach(Control aChild in aControl.Controls) For''''''Each''''''Child(aChild,aProc); } public static IList Convert''''''All(IEnumerable aList, Unary''''''Function toEvalOn) { Array''''''List result = new Array''''''List(); foreach(object anObject in aList) { object processed = toEvalOn.Eval(anObject); if(processed!=null)result.Add(processed); } return result; } public static int Matches(IEnumerable aList, Unary''''''Predicate match) { int result=0; foreach(object anObject in aList) if(match.Is(anObject)) result++; return result; } public static IList Reverse(IEnumerable aList) { Stack aStack = new Stack(); foreach(object each in aList)aStack.Push(each); Array''''''List result = new Array''''''List(); while(aStack.Count>0)result.Add(aStack.Pop()); return result; } } ---- Why oh why oh why did they use the keyword "delegate" instead of "do"? Didn't the language designers think about how code is read? It's the same as saying "if you're hungry delegate eat a banana" instead of "if you're hungry do eat a banana". In code terms, this would read so much more pleasantly: button.Click += do { window.Close(); } Or employees.Each( do(Employee e) { e.Salary += bonus; }); ''Fixed to some extent by the lambda operator added in 3.0. => is read as "goes to", according to the docs.'' employees.Each( (e) => e.Salary += bonus ); ---- See also CoroutinesInDotNet for a link to a implementation of coroutines using fibers. ---- CategoryCeeSharp CategoryClosure