# Local functions — a function declared inside a body

> A local function is a helper declared inside the body that uses it — `int Sq(int x) => x * x;`. It can be called before or after its declaration, can call itself, reads the parameters and typed locals of the code around it, and shares what it assigns with that code, as in C#. A `static` local function reads nothing from around it.

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

## Summary        {#summary}
A helper that belongs to one body, declared in it:

```osy title="a local function, a recursive one, and one called before its declaration" run app=function-local-functions
string Report(int count) {
  int margin = 2;
  var line = Label(count);                    // called before it is declared, as C# allows

  string Label(int n) => $"#{n + margin}";    // reads `margin` from the code around it
  int Fact(int n) => n <= 1 ? 1 : n * Fact(n - 1);    // calls itself

  return $"{line}|{Fact(count)}";
}

[Test]
void Local_Functions_Work_Like_Methods() {
  Assert.Equal("#6|24", Report(4));
}
```

## Signature      {#signature}
```osy syntax
<Return> Name(<params>) { … }
<Return> Name(<params>) => <expression>;
static <Return> Name(<params>) => <expression>;     // reads nothing from the code around it
```

## Description    {#description}

### What can a local function read?   {#captures}
The parameters of the function it is in, and the locals declared there with their TYPE spelled out — `int margin = 2;`,
not `var margin = 2;`. A local function receives what it reads as a value, so a `var` local it reads is refused with a
message asking for the type. Inside a class method it also reads the class's own fields, exactly as the method does:

```osy title="a local function inside a method reads the method's object" run app=function-local-functions
class Invoice {
  public decimal Rate = 0.25m;

  public decimal Gross(decimal net) {
    decimal WithTax(decimal v) => v * (1m + Rate);
    return WithTax(net);
  }
}

[Test]
void A_Method_Local_Reads_The_Object() {
  Assert.Equal(125m, new Invoice().Gross(100m));
}
```

### Can it change a variable of the code around it?   {#writes}
Yes, as in C#: the local function and the body around it share the variable. What it reads is read when it is CALLED,
and what it assigns is the variable itself — also when one local function calls another, or calls itself:

```osy title="a local function that writes a variable of the code around it" run app=function-local-functions
[Test]
void A_Local_Function_Shares_What_It_Writes() {
  int seen = 0;
  int step = 1;
  void Note() { seen += step; }
  int NoteTwice() { Note(); Note(); return seen; }
  step = 5;
  Note();
  Assert.Equal(15, NoteTwice());
  Assert.Equal(15, seen);
}
```

Such a local function is called by NAME in the body that declares it. Used as a value — `Action a = Note;`, handed on
or stored — it could run where the variable is not, so that is refused by name; and it cannot wait inside itself for
the other side or a durable timer. In either case, have it return the new value and assign it where the variable
lives.

### What does `static` add?   {#static}
A promise that the local function reads nothing from around it — C#'s `static` local function. One that does is
refused, as C# refuses it.

## See also       {#see-also}
- [function](https://osysharp.com/reference/function/declaration/) — functions declared at the top level of a file
- [x => … — lambdas, with or without parameter types](https://osysharp.com/reference/function/lambda/) — an inline function as a value
- [class methods](https://osysharp.com/reference/class/methods/) — functions that belong to a class
