# foreach

> Walks a collection — a query result, a list, or a parent's children. The normal way to iterate; reach for a for loop only when you need the index.

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

## Summary        {#summary}
`foreach` walks a collection, binding each element to a local. It is the normal loop: a materialised query result, a
`List<T>`, or a parent's children all iterate the same way.

## Signature      {#signature}
```osy syntax
foreach (var <item> in <collection>) { … }
```

## Description    {#description}

### Walking a query result   {#query}
Materialise the query with `.ToList()`, then walk it:

```osy title="summing what a query returned" test app=function-foreach
entity Order {
  [Required] string Code;
  decimal Total;
}

decimal TotalOver(decimal threshold) {
  var sum = 0m;
  foreach (var o in Order.Where(x => x.Total > threshold).ToList()) {
    sum += o.Total;
  }
  return sum;
}
```

Note the accumulator is seeded `0m`, not `0` — see [var](https://osysharp.com/reference/function/var/).

### Walking a parent's children   {#children}
A parent's collection member iterates directly. This is the connected path through the object graph, and the reason
you should never fetch children with a separate filtered query ([relations](https://osysharp.com/reference/entity/relations/)):

```osy title="walking the children you already loaded" test app=function-foreach
entity Invoice {
  [Required] string Number;
  [ForeignKey(Invoice)] InvoiceLine[] Lines;
}

entity InvoiceLine {
  [Required] Invoice Invoice;
  decimal Amount;
}

decimal InvoiceTotal(string number) {
  var inv = Invoice.Single(i => i.Number == number);
  var total = 0m;
  foreach (var line in inv.Lines) {
    total += line.Amount;
  }
  return total;
}
```

### Walking a list   {#list}
```osy title="iterating a list" test app=function-foreach
string Join(string csv) {
  var joined = "";
  foreach (var part in Text.Split(csv, ",")) {
    joined += Text.Trim(part);
  }
  return joined;
}
```

### Walking the characters of a string   {#chars}
A string is a sequence of one-character strings, so `foreach` walks it exactly as it walks a list — there is no
separate character type to learn, and `ch` is an ordinary `string` you can compare, append and pass on:

```osy title="a character at a time, and what `ch` is" syntax
int Commas(string line) {
  var n = 0;
  foreach (var ch in line) { if (ch == ",") { n = n + 1; } }
  return n;
}
```

The loop lowers to `Text.Chars(line)`, which you may also call directly when you want the characters as a
`string[]` rather than a loop — `Text.Chars("abc")` is `["a", "b", "c"]`.

### Walking a stream   {#stream}
A `stream<T>` function hands out its items over time ([yield — a function that produces results over time](https://osysharp.com/reference/function/yield/)). A loop is how they are read, in any
function or test: `foreach`, or C#'s `await foreach` — the two are the same loop.

```osy title="a function reading a stream" test app=foreach-stream
stream<int> Count(int n) {
  for (var i = 1; i <= n; i = i + 1) { yield return i; }
}

int Sum(int n) {
  var total = 0;
  foreach (var x in Count(n)) { total = total + x; }
  return total;
}
```

```osy title="…and a test reads one the same way" run app=foreach-stream
[Test]
void a_test_reads_a_stream_with_a_loop() {
  List<int> seen = [];
  foreach (var x in Count(3)) { seen.Add(x); }
  Assert.Equal(3, seen.Count);
  Assert.Equal(6, Sum(3));
}
```

**The loop reads the stream as it comes**, in every body that runs on the server: the body runs once per item, as
each arrives. So a loop can leave early — `break`, `return` — and the stream stops being read, and a stream that
never ends (a folder being watched, a program's output) can be read up to the item you were waiting for:

```osy title="leave when you have what you came for" syntax
string FirstError(Guid program) {
  foreach (var line in Host.Process.Watch(program)) {
    if (line.IsError) { return line.Text; }      // the rest is not read
  }
  return "";
}
```

**One thing changes that: a body that has to wait.** When the code inside the loop waits on something outside the run
— a function that runs in the browser, a person's answer, a durable delay — the run is put away and picked up later,
and a half-read stream cannot be put away. At that moment the rest of the stream is read to its end, and the loop
carries on over what arrived. Nothing is lost and nothing is repeated; but a stream that never ends cannot be waited
in the middle of, so do the waiting before or after such a loop. Inside a `stream<T>` function this never happens — a
producer does not wait that way.

A component does not loop over a stream in its own code at all: it binds it to a `live var` and renders it
([The reactivity & lifecycle model](https://osysharp.com/reference/ui/reactivity/)).

### Can the loop variable have a type?   {#typed}
Yes — `foreach (int x in arr)` and `foreach (char c in "abc")` are C#'s typed loop variables, and the type is checked
against the elements as a declaration's is. `var` remains the usual spelling.

```osy title="a typed loop variable" test app=foreach-typed
int Total(int[] xs) { int t = 0; foreach (int x in xs) { t += x; } return t; }
```

### When you need the index   {#index}
`foreach` gives you the element, not its position. When the position is what you are after, use a
[`for`](https://osysharp.com/reference/function/for-loop/) loop.

### How do I stop part-way through?   {#leaving}
`break` and `continue` work as they do in C# — see [break / continue](https://osysharp.com/reference/function/break-continue/).

## See also       {#see-also}
- [for](https://osysharp.com/reference/function/for-loop/) — when you need the index
- [break / continue](https://osysharp.com/reference/function/break-continue/) — leaving a loop, or skipping an element
- [relations](https://osysharp.com/reference/entity/relations/) — why children are walked through the collection
- [Where / Single / Count](https://osysharp.com/reference/query/where/) — producing the result you walk
