# 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"]`.

### 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
