Osy#betaRun it on Osyrin: osyrin.com

Reference / Function

Local functions — a function declared inside a body

<Return> Name(<params>) { … } // inside a function or method body static <Return> Name(<params>) => …;

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.

stable3 examples compiled by CIfunctionconstructcsharp

Summary#

A helper that belongs to one body, declared in it:

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#

<Return> Name(<params>) { … }
<Return> Name(<params>) => <expression>;
static <Return> Name(<params>) => <expression>;     // reads nothing from the code around it

Description#

What can a local function read?#

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:

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

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:

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

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#

Related

function

A function is a top-level unit of work, written like a C# method — a return type, a name, typed parameters, a body. It…

x => … — lambdas, with or without parameter types

A lambda is an inline function: a parameter list, `=>`, and a body. Its parameter types come from where it is used, or…

class methods

Behaviour attached to a class — a method with a receiver, called as value.Method(). Classes are in-memory values, so a…