# IEnumerable<T> with yield return — iterators

> A function declared `IEnumerable<T>` whose body uses `yield return` is a C# iterator: each `yield return` adds one item to the sequence it hands back, and `yield break` ends it early. The caller gets the whole sequence — `foreach`, LINQ, `.Count()` and `.ToList()` all work on it.

<!-- id: function-iterators · area: function · stability: stable · html: https://osysharp.com/reference/function/iterators/ -->

## Summary        {#summary}
Write the C# iterator you would write anywhere else:

```osy title="an iterator, read by foreach and by LINQ" run app=function-iterators
IEnumerable<int> Evens(int upTo) {
  for (int i = 0; i <= upTo; i += 2) {
    yield return i;
  }
}

[Test]
void An_Iterator_Hands_Back_Its_Sequence() {
  var seen = new List<int>();
  foreach (var n in Evens(6)) seen.Add(n);
  Assert.Equal(4, seen.Count);
  Assert.Equal(12, Evens(6).Sum());
  Assert.Equal("4,6", string.Join(",", Evens(6).Where(n => n > 2)));
}
```

## Signature      {#signature}
```osy syntax
IEnumerable<T> Name(<params>) {
  …
  yield return <item>;     // add one item to the sequence
  …
  yield break;             // end the sequence here
}
```

## Description    {#description}

### How do I end the sequence early?   {#yield-break}
`yield break;` ends it with what was produced so far — the same as reaching the end of the body:

```osy title="yield break inside an endless loop" run app=function-iterators
IEnumerable<int> UpTo(int n) {
  for (int i = 0; ; i++) {
    if (i >= n) yield break;
    yield return i;
  }
}

[Test]
void Yield_Break_Ends_The_Sequence() {
  Assert.Equal(3, UpTo(3).Count());
}
```

### What does the caller hold?   {#what-the-caller-gets}
The whole sequence, as Osy#'s read-only sequence type — so `var xs = Evens(10);` is an `int[]` and everything an array
does works on it. A parameter or local may say it holds one as `IEnumerable<int>` too — the collection interfaces
are the collections they name ([IEnumerable<T>, IReadOnlyList<T>, IList<T> — the collection interfaces](https://osysharp.com/reference/types/collection-interfaces/)).

### When is the sequence produced?   {#eager}
When the iterator is CALLED, all at once — C# produces it one item per step of the caller's loop instead. The answer
is the same for every iterator that ends; what differs is only WHEN its body runs relative to its reader's.

### An iterator that never ends   {#endless}
An iterator whose loop can never end is meant to be cut short by its reader, and it is — the reader says how many items
it needs, and the iterator stops there:

```osy title="an endless iterator, cut short" run app=function-iterators
IEnumerable<int> Naturals() {
  int i = 0;
  while (true) { yield return i++; }
}

[Test]
void An_Endless_Iterator_Is_Cut_Short_By_Its_Reader() {
  Assert.Equal(10, Naturals().Take(5).Sum());
  Assert.Equal(12, Naturals().Where(x => x % 3 == 0).Select(x => x * 2).First(y => y > 10));
  Assert.Equal(4, Naturals().TakeWhile(x => x < 4).Count());
  Assert.True(Naturals().Contains(42));
}
```

The readers that can say how much they need are `.Take(n)` (also `.Skip(k).Take(n)`), `.First()`, `.FirstOrDefault()`
and `.Any()` — each with or without a predicate — `.ElementAt(i)`, `.TakeWhile(…)` and `.Contains(x)`, with any
`.Where(…)` and `.Select(…)` between the call and the reader. Any other reader of an endless iterator — a `foreach`, a
`.ToList()`, a `.Count()` — would never finish, in C# as here, and is a compile error that names the readers above. A
`foreach` that `break`s out of an endless iterator is one of those: write the stopping point as the reader
(`foreach (var n in Naturals().TakeWhile(x => x < 100))`).

The iterator METHOD of a class keeps the older rule — its loop needs a way out — because its call sites cannot yet hand
it what its reader needs; declare it as a top-level function to read it this way.

A sequence whose items arrive over TIME — a long query, a model's streamed answer — is a different thing with its own
declaration: [yield — a function that produces results over time](https://osysharp.com/reference/function/yield/) (`stream<T>`), which a page watches as it fills.

## See also       {#see-also}
- [yield — a function that produces results over time](https://osysharp.com/reference/function/yield/) — `stream<T>`: items that arrive over time, to a `live var`
- [foreach](https://osysharp.com/reference/function/foreach/) — reading a sequence item by item
- [LINQ over a local list](https://osysharp.com/reference/query/in-memory-linq/) — `Where`, `Select`, `Sum` and the rest over a sequence in hand
