# Optional and required members

> A member is required or optional by how you spell its type. A bare value type with a natural zero reads that zero; a bare value-shaped type with no natural zero (string, enum, date, id) is REQUIRED — you must give it a value. Add `?` to make any member optional (it reads back null). Entity references are the one exception: a bare reference is optional, and you write `[Required]` to demand it.

<!-- id: types-optional-and-required · area: types · stability: stable · html: https://osysharp.com/reference/types/optional-and-required/ -->

## Summary        {#summary}

Whether a member is required or optional is carried by its **type spelling** — there is no separate keyword to
remember. A bare member is non-nullable; the `?` suffix makes it optional (it reads back `null`). What "bare" *means*
depends on whether the type has a natural zero:

- A value type with a **natural zero** — `int`, `long`, `double`, `decimal`, `bool`, `TimeSpan` — reads that zero when
  left unset. `int Count;` reads back `0`, exactly as a C# field would.
- A value-shaped type with **no natural zero** — `string`, any `enum`, `DateTime`/`DateOnly`/`TimeOnly`, `Guid`,
  `Json` — is **required**: the platform invents no value for it, so you must supply one before the row is saved.
- An **entity reference** is the exception: a bare reference is **optional**. Write `[Required]` to demand it.
- A **`Markdown`** member is also optional, for a different reason: it holds a document stored as its own sections, so
  a document nobody has written simply is not there and there is nothing to supply. See [Markdown](https://osysharp.com/reference/types/markdown/).

## Signature      {#signature}

```osy syntax
entity Ticket {
  string Title;                 // REQUIRED  — a bare string has no natural zero, so you must set it
  string? Note;                 // optional  — reads back null when unset
  int Priority;                 // reads back 0 (int has a natural zero)
  Status State;                 // REQUIRED  — an enum has no natural zero
  Status State2 = Status.Open;  // optional-with-a-default — the default supplies the value
  DateTime? ResolvedAt;         // optional  — null until it is resolved

  Customer Reporter;            // OPTIONAL  — references are optional by default
  [Required] Team Team;         // required  — opt a reference in with [Required]
}
```

## Description    {#description}

### Three ways to spell a member   {#spellings}

Every member falls into one of three shapes:

1. **Bare** (`string Title;`) — non-nullable. For a natural-zero type this reads the zero; for everything else it is
   **required**.
2. **Optional** (`string? Note;`) — nullable. Reads back `null` when nobody set it.
3. **Defaulted** (`Status State = Status.Open;`) — non-nullable, but you supplied the value once at the declaration,
   so the row is never without one.

### Why a bare `string` is required   {#bare-string}

In C#, `default(string)` is `null`, not `""`. An empty string is a *value someone typed*, not the absence of one —
conflating them hides bugs. So Osy# does not invent an empty string for you: a bare `string Title;` must be given a
value by the time the row is saved. If you genuinely want "maybe unset," say so with `string? Title;`, which reads back
`null`. The same reasoning covers `DateTime`, `Guid`, and `Json` — there is no honest "zero" of those types to fall
back on.

### Enums are required, not silently first   {#enums}

A bare `enum` is **required**. It is *not* quietly defaulted to whichever member you happened to list first —
reordering the members would silently change the stored default, and a value at position zero may not even be a member
you named. Give it an explicit default when you want one (`Status State = Status.Open;`), make it optional
(`Status? State;`), or supply it before the row is saved.

### References are optional by default   {#references}

An entity reference is the deliberate exception. The everyday shape is: create the row, *then* let the user pick the
related record from a dropdown — so demanding the reference at creation would be wrong. A bare `Customer Reporter;` is
therefore **optional** (reads back `null`). When a reference truly must be present, mark it `[Required] Team Team;`.

### When a required member is checked   {#when-checked}

"Required" means *present when the value becomes real* — and that moment depends on what you are building:

- **Entities are saved**, so a required entity member is checked when you **commit** the row. This is what makes the
  everyday create-form work: seed an empty draft (`draft = new Ticket {}`), bind each field to an input, and let the
  user fill it — the required members are checked when the row is saved, not while it is still being typed. Commit a row
  with a required member still unset and it is refused, naming the member.
- **A `class` is a transient value** with no save step, so its required members are checked at **construction** — the
  compiler stops you at `new`, naming the member and the three fixes:

  ```osy syntax
  new Receipt { }         // error: 'Receipt.Number' must be given a value — set it here
                          //        (new Receipt { Number = … }), give it a default (Number = …;),
                          //        or make it optional (string? Number;).
  ```

## Examples       {#examples}

A bare `string` parameter is required; the `?` suffix makes one optional and it reads back `null` — the same spelling
rule that governs entity members, shown here on ordinary values so it compiles on its own.

```osy title="a required name and an optional nickname" test app=text-search
string DisplayName(string name, string? nickname) {
  // `name` is required (a bare string); `nickname` is optional (`?`), so it may be null.
  return nickname == null ? name : name + " (" + nickname + ")";
}
// DisplayName("Ada", null)   ->  "Ada"
// DisplayName("Ada", "Countess")   ->  "Ada (Countess)"
```

## See also        {#see-also}

- [DateTime](https://osysharp.com/reference/types/datetime/) — a bare `DateTime` is required; use `DateTime?` for "unset until it happens".
- [enum](https://osysharp.com/reference/enum/declaration/) — declaring enums and their defaults.
- [entity](https://osysharp.com/reference/entity/declaration/) — declaring entities, references, and `[Required]`.
