# `static` methods

> A `static` method belongs to the type rather than to any instance, and is called on the type name — `Money.Round(x)`. It has no `this`, so it cannot read the class's instance fields; it can call the class's other static methods and read its `const` values by bare name. Fields cannot be static: a `const` covers the fixed values, and anything that would need to change belongs to an instance or to an entity.

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

## Summary        {#summary}
A `static` method is called on the type, not on a value:

```osy title="a static method, called on the type name" test app=class-static
class Money {
  public decimal Amount;

  public static decimal Round(decimal value) {
    return Math.Round(value, 2);
  }
}

decimal RoundAPrice() {
  return Money.Round(19.999m);       // on the TYPE — there is no Money instance here
}
```

Reach for it when the operation is about the type but not about any particular value of it — a conversion, a
validation, a calculation over its arguments.

## Signature      {#signature}
```osy syntax
static <Return> <Name>(<params>) { … }
public static <Return> <Name>(<params>) { … }
```

`static` goes after the visibility word, as in C#. It applies to methods only.

## Description    {#description}

### A static method has no `this`   {#no-this}
That is the whole of the rule, and everything else follows from it. There is no instance, so there is nothing for an
instance field to be read from:

```osy title="✗ a static method reaching for instance state" syntax
class Money {
  public decimal Amount;

  public static decimal Doubled() {
    return Amount * 2m;              // ✗ 'Amount' belongs to an INSTANCE
  }

  public static decimal Half() {
    return this.Amount / 2m;         // ✗ `this` has no meaning in a static method
  }
}
```

Take the value as a parameter instead — which is usually what the method wanted anyway:

```osy title="pass in what the method needs" test app=class-static
class Tax {
  public static decimal Net(decimal gross, decimal rate) {
    return gross / (1m + rate);
  }
}
```

### What a static method CAN see of its own class   {#what-it-sees}
Its other static methods and its `const` values, both by bare name — the same rule as C#:

```osy title="statics reach statics, and consts, unqualified" run app=class-static
class Rate {
  public const decimal Standard = 0.25m;

  public static decimal Apply(decimal amount) {
    return amount * (1m + Standard);      // a const, by bare name
  }

  public static decimal ApplyTwice(decimal amount) {
    return Apply(Apply(amount));          // another static, by bare name
  }
}

[Test]
void Statics_Reach_Statics_And_Consts() {
  Assert.Equal(125m, Rate.Apply(100m));
  Assert.Equal(156.25m, Rate.ApplyTwice(100m));
}
```

An **instance** method may call its class's static methods the same way — it simply does not pass its `this` along:

```osy title="an instance method calling its type's static" test app=class-static
class Line {
  public decimal Gross;

  public decimal Net() {
    return Tax.Net(Gross, 0.25m);
  }
}
```

### Call it on the type, never through a value   {#call-form}
The two directions are both compile errors, and each says which spelling to use:

```osy syntax
var m = new Money { Amount = 1m };

m.Round(2.5m);          // ✗ 'Money.Round' is static — call it as `Money.Round(…)`
Money.Amount;           // ✗ 'Money.Amount' is an instance member — access it through an instance
```

Refusing the first is C#'s rule too, and it is worth the strictness: `m.Round(…)` reads as though the method can see
`m`, and it cannot — the receiver would be evaluated and discarded.

### Statics inherit   {#inheritance}
A static method declared on a base class is callable on a derived one, like any other inherited member:

```osy title="a subclass inherits its base's statics" test app=class-static
class Shape {
  public string Name;
  public static decimal Zero() { return 0m; }
}

class Circle : Shape {
  public decimal Radius;
}

decimal ZeroThroughTheSubclass() {
  return Circle.Zero();          // Shape declares it; Circle inherits it
}
```

It cannot be `virtual`, `override` or `abstract`, and combining them is a compile error. Those words choose a body
from the *receiver's* runtime type, and a static call has no receiver to choose by.

### Static methods overload   {#overloads}
Exactly like instance methods — a name maps to a set, and the call site picks by the arguments. See
[Method overloads](https://osysharp.com/reference/class/overloads/) for the rule.

```osy title="two statics sharing a name" test app=class-static
class Fmt {
  public static string Of(decimal d) { return d.ToString(); }
  public static string Of(decimal d, string unit) { return d.ToString() + " " + unit; }
}
```

### Fields cannot be static   {#no-static-fields}
`static` applies to methods only. A static **field** would be mutable state shared by every application running in
the host process, with no per-app copy to reset — so it is refused, in as many words:

```osy syntax
class Counter {
  public static decimal Total;         // ✗ cannot be `static`
}
```

There are three things people reach for it for, and each has its own answer:

| what you want | reach for |
|---|---|
| a fixed value the whole program shares | `const` — already static, and needs no modifier |
| a value that belongs to one object | an ordinary field |
| state that outlives a request | an `entity` — stored, per-app, and secured |

For the same reason there is no static **constructor**: it would exist to initialize static state, and there is none.

## See also       {#see-also}
- [class methods](https://osysharp.com/reference/class/methods/) — instance methods, and the member-body surface a static method shares
- [Method overloads](https://osysharp.com/reference/class/overloads/) — how a call site picks from a set of same-named methods
- [Classes](https://osysharp.com/reference/class/index/) — fields, `const`, and what a class is
- [type visibility (public / internal)](https://osysharp.com/reference/types/visibility/) — `public`, `private` and `protected`, which combine with `static`
