In the last post I have described how enumeration works in Delphi. Now I will try to expand the subject a bit and make a more general description of what enumerability actually means and how it can solve some basic problems and patterns.

“*An enumrebale is not necessarily a collection*“. You should keep in mind that enumerability doesn’t apply only to collections. It is a more abstract concept. Enumeration can apply to any kind of sequence — abstract, mathematical or a collection. As an example let’s talk about streams — streams are also enumerables, in some cases these behave exactly like enumerable collections: For streams that do not have a defined size (like for example downloading a file over a HTTP stream that doesn’t say the file size). All you can do in these cases is to read bytes from the stream until you read the bottom and receive an *EOF* notification.

“*Abstract vs concrete sequences*“. An **abstract** sequence in my definition is one that doesn’t occupy space and each new element is generated on the fly by the enumerable. A **concrete** sequence is more akin to a collection which already has its elements stored somewhere and all it does is to fetch them when enumerating.

In the next example I took a known mathematical sequence which I am sure all of you are acquainted with: the Fibonacci sequence; and created an abstract enumerable which at each iteration calculates the next number:

type TFibonacciEnumerator = record private FCurrent, FPrev, FCount, FMaxCount: Cardinal; function GetCurrent: Cardinal; public { Move to the next calculation } function MoveNext(): Boolean; { Reads the current number } property Current: Cardinal read GetCurrent; end; Fibonacci = record private FLimit: Cardinal; public { Returns the enumerator object } function GetEnumerator(): TFibonacciEnumerator; { Static function that } class function OfLength(const ALength: Cardinal): Fibonacci; static; end; { TFibonacciEnumerator } function TFibonacciEnumerator.GetCurrent: Cardinal; begin Result := FCurrent; end; function TFibonacciEnumerator.MoveNext: Boolean; var LTemp: Cardinal; begin { Check if the end of the chain } if FCount >= FMaxCount then Exit(false); Result := true; { Make the next calculation } if FCount <= 1 then FCurrent := FCount else begin LTemp := FCurrent; FCurrent := FCurrent + FPrev; FPrev := LTemp; end; Inc(FCount); end; { Fibonacci } function Fibonacci.GetEnumerator: TFibonacciEnumerator; begin Result.FCurrent := 0; Result.FPrev := 0; Result.FCount := 0; Result.FMaxCount := FLimit; end; class function Fibonacci.OfLength(const ALength: Cardinal): Fibonacci; begin if ALength = 0 then raise EArgumentOutOfRangeException.Create('ALength should be > 0'); Result.FLimit := ALength; end; var Number: Cardinal; begin { Show the first 100 Fibonacci numbers } for Number in Fibonacci.OfLength(100) do WriteLn(Number); ReadLn; end.

What is cool about this example is the fact that you do not occupy any memory with the calculated numbers, those are made on-the-fly.

This example did not demonstrate another important aspect of enumerables and exactly: “*materializing*” abstract sequences. If my Fibonacci record was actually a class derived from *TEnumerable<Cardinal>*, I could have written this:

var List: TList<Cardinal>; begin List := TList<Cardinal>.Create(Fibonnaci.OfLength(100)); end.

This would have “*materialized*” the abstract sequence generated by the *Fibonacci* object and stored each value in a *concrete* sequence (the List collection).

Unfortunately Delphi’s generics support is at it’s infancy so not many features are yet available in the standard classes to exploit the power of Enumerables. I predict this will change over time and more cool stuff will appear either directly in the RTL or in form of 3rd-party libraries.