So what if we could do something like this?
for i in Power(2, 10) do begin Writeln(i); end;
Well, you can! All you need is define the function as follows:
function Power(ANumber, AExponent: Integer): IEnumerable<Integer>; begin Result := TDelegateEnumerable<Integer>.Create( procedure var i, k: Integer; Result: Yield<Integer>; begin k := 1; for i := 1 to AExponent do begin k := k * ANumber; Result := k; end; end); end;
Looks pretty much simple and straight forward, eh?
So what happens there? Well basically it creates some TEnumerable<T> descendant which takes a TProc as parameter and executes it when GetEnumerator is called. Well but thats only half the truth. The real magic happens when you assign a value to that Yield<Integer> variable. And that's basically a record with some implicit operator overload which makes the worker thread or fiber (for now you can only set that with a compiler switch in the Collections.Yield.pas) continue and make the Enumerator do his MoveNext and provide the value for the GetCurrent.
I also implemented support for Alex Ciobanu's awesome collection library (you can also set that up with a compiler switch in the Collections.Yield.pas). Then you can do something funny like this (provided that you set the result type of your function to IEnexCollection<T>):
for i in Power(2, 10).Reversed do begin Writeln(i); end;
Ok, you might say, I can do all that with getting my values and putting them into some list and I can easily go through it with any loop I want. True, but then you will either have to wait until your calculation and processing is done and the list is generated. And also you have to carry around the list and the elements in it. What if you just want to set up some parameters and calculate the result later? Well with that implementation you can since the enumeration procedure is just called when GetEnumerator is called.
So, pretty cool, no? What do you think?
P.S.: The full source code is available on google code as always.