Na blogu Paula Vicka, jednoho z lidí, kteří se přímo podílejí na vývoji a rozšiřívoání jazyka Visual Basic, vyšel zajímavý článek na téma iterátory. V jazyce C# jsou už poměrně dlouho, vypadá to nějak takto:
private IEnumerable<int> Seq(int top)
{
for (int i = 0; i < top; i++)
yield return i;
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (int i in Seq(5))
MessageBox.Show(i.ToString());
}
Jak to funguje? Máme funci Seq, která obsahuje cyklus od 0 do top - 1, kde top je parametr, který jsme funkci předali. V každém kroku cyklu se provede příkaz yield return i, to znamená, že se vrátí aktuální hodnota proměnné i, ale díky klíčovému slovu yield se výsledek předá jako prvek kolekce. Všimněte si, že funkce vrací IEnumerable<int>, což je kolekce nějakých integerů. Metoda se tedy zavolá a jednotlivé prvky kolekce "generuje" voláním yield return. Jakmile doběhne cyklus, dojde se na konec funkce a kolekce se uzavře, další prvky už nemá.
Takže zavoláním Seq(5) nám brátí kolekci čásel 0,1,2,3 a 4. Když ji foreach cyklem projdeme a pro každý prvek zobrazím MessageBox, uvidíme přesně tato čísla.
A přesně tohle bude velmi pravděpodobně umět i nový Visual Basic, jen syntaxe bude trochu složitější a robustnějši:
Tento kousek kódu jsem si vypůjčil z dotyčného článku, podstatná je první metoda. Iterator a End Iterator ohraničují iterátor, ten je v tomto případě "anonymní", nemá žádný název. Klidně můžeme napsat něco jako Dim kolekce = Iterator: Return 123: Return 13: End Iterator. Je to prostě způsob, jak vygenerovat kolekci prvků.
Zajímavá featura, kterou už C# nemá, je možnost začlenit do generované kolekce kolekci jinou, to je to Return Each kolekce, což prostě do kolekce, kterou aktuálně generujeme, vrazí prvky z předané kolekce (ať už vznikla, jak chtěla, na tom nesejde, může to být obyčejné pole).
V komentářích se ale objevilo několik zajímavých názorů, že když už jsou iterátory anonymní, proč by nemohly být ty obyčejné, které by vypadaly třeba takto:
Public Iterator MujIterator()
Return 1
Return 2
Return 3
End Iterator
Toto řešení je sice hezké a konzistentní, ale co když budu chtít mít vlastnost vracející vygenerovanou kolekci. Pak budu stejně muset použít iterátor anonymní. Někoho tam ještě napadlo tohle:
Public Iterator Function MujIterator()
Return 1
Return 2
Return 3
End Function
Tato syntaxe by byla kompatibilní i s vlastnostmi, prostě bychom napsali Public Iterator ReadOnly Property ... a bylo by, ale na druhou stranu už to není konzistentní, tady totiž končíme pomocí End Function, kdežto anonymní iterátor končí End Iterator. Co se mě týče, buď bych nechal jen anonymní iterátory, nebo jen obyčejné. Raději bych ty anonymní, mají univerzálnější použití, i když v drtivé většině případů se stejně budou používat ve funkcích nebo vlastnostech.