# Structs

> A `struct` is a VALUE type, as in C#: assigning one, passing one, returning one or putting one in a list stores a COPY, so a change through one name is never seen through another. An unset struct — a field, a local — is its default, every member zero, never null. It compares by its members through `Equals`; a `record struct` adds `==`.

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

## Summary        {#summary}
A struct copies where a class would share:

```osy title="assignment copies" test app=class-structs
struct Point { public int X; public int Y; }

int Copy() {
  Point a = new Point();
  a.X = 1;
  Point b = a;      // a copy
  b.X = 2;
  return a.X;       // 1 — `a` was never touched
}
```

## Signature      {#signature}
```osy syntax
struct Name { public int X; public Name(int x) { X = x; } }   // fields, constructors, methods — as a class
readonly struct Name { … }                                     // C#'s promise that it is not changed after it is made
record struct Name(int X, int Y);                              // a struct with a record's members, == included
Name n;          // a struct local is its DEFAULT, every member zero — `n.X = 3;` may follow
a.Equals(b)      // member by member
```

## Description    {#description}

### Where the copy happens   {#copies}
Everywhere a struct is STORED: a local (`Point b = a;`), an assignment, an argument (the callee changes its own
copy), a returned value, a field of another type, and an element of a collection (`points.Add(p)` adds a copy).
Writing a member through the place that holds it changes that place — `a.X = 1;`, `holder.Position.X = 5;` — which
is what makes a struct field of a class usable at all.

### Its default   {#default}
A struct is never null. A field of a struct type with no initializer starts at the struct's default — every member
at its own default — and so does a local declared without a value. `Point? p;` is the spelling for "maybe none".

### Equality   {#equality}
`a.Equals(b)` compares every member, and `Distinct`, `Contains` and a dictionary key use the same rule. A plain
struct has no `==`, as in C# — write `Equals`, or declare it a `record struct`, which has both.

### `readonly`   {#readonly}
`readonly struct` and a struct's `readonly` method (`public readonly int Sum() => X + Y;`) are accepted where C#
accepts them. Every call already reads the value as it stands, so neither changes an answer.

### Not a `ref struct`   {#ref-struct}
A `ref struct` is confined to the stack, and an Osy# body can suspend and resume later, on another machine — there
is no stack to confine it to. It is refused by name; declare a `struct`.

## Examples       {#examples}

```osy title="a struct field of a class, and a struct in a list" test app=class-structs-field
struct Point { public int X; public int Y; }
class Shape { public Point Origin; }

int Place() {
  var s = new Shape();          // Origin is (0, 0), not null
  s.Origin.X = 5;               // writes the field itself
  var list = new List<Point>();
  list.Add(s.Origin);           // a copy goes into the list
  s.Origin.X = 9;
  return list[0].X;             // 5
}
```

```osy title="a record struct compares with ==" test app=class-structs-record
record struct Pos(int X, int Y);

bool Same() {
  var p = new Pos(1, 2);
  return p == new Pos(1, 2) && (p with { Y = 3 }).Y == 3;   // true
}
```

## Errors         {#errors}

| Message | Cause | Fix |
|---|---|---|
| `` `==` is not defined on the struct 'X' `` | A plain struct has no `==`, as in C#. | Write `a.Equals(b)`, or declare it `record struct X`. |
| `` Osy# has no `ref struct` `` | A stack-only type has no stack to live on in a durable body. | Declare a `struct`. |
| `` `struct X(…)` — a struct's parameter list is a primary constructor `` | A plain struct with a parameter list. | Write `record struct X(…)`, or declare the fields and a constructor. |

## See also       {#see-also}
- [Records](https://osysharp.com/reference/class/records/) — compared by members, and the `record struct`
- [Comparing classes](https://osysharp.com/reference/class/equality/) — identity for a class, members for a record or a struct
- [Classes](https://osysharp.com/reference/class/index/) — classes, and when to use one
- [Copying a class with changes](https://osysharp.com/reference/class/with/) — a copy with some members replaced
