# long

> A 64-bit whole number, exact to its full range — ids, sequence numbers, row versions, byte offsets. It holds the same value whether your code runs on the server or in the browser, including past the point a floating-point number would start rounding.

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

## Summary        {#summary}

A 64-bit whole number, exact across its entire range — roughly ±9.2 quintillion. Use it for values that are counted or
issued rather than measured: ids, sequence numbers, row versions, byte offsets. Like every other value in Osy#, a
`long` holds the same value wherever the code runs.

## Signature      {#signature}

```osy syntax
long Sequence = 9007199254740993;
int  Count    = 42;                  // `int` is 32-bit — plenty for a count
```

## Description    {#description}

Reach for `long` when a number is an **identity or a position**, not a measurement. An id issued by a sequence, a
version stamp, an offset into a file — these are values where being off by one is not a small error, it is the wrong
record. `int` covers ordinary counts and indexes; use `long` when the range could plausibly exceed about two billion,
or when the value comes from a system that issues 64-bit ids.

### Division truncates   {#division}

Whole-number division discards the remainder rather than rounding — `7 / 2` is `3`, and `-7 / 2` is `-3`. The remainder
operator takes the sign of the left operand, so `-7 % 2` is `-1`.

```osy title="whole-number division discards the remainder" syntax
7 / 2          // 3    — not 3.5, and not 4
-7 / 2         // -3   — truncated toward zero
-7 % 2         // -1   — the sign follows the dividend
```

This holds **anywhere in an expression**, not only when the two operands are written side by side. A whole-number
expression stays a whole-number expression however many steps it takes to get there, so a division at the end of a
chain truncates exactly as a direct one does.

```osy title="a chain of whole numbers still truncates at the end" syntax
(3 - 1) / 3    // 0    — the subtraction is still whole-number arithmetic
(9 - 1) / 3    // 2
count * 2 / 3  // truncates; every operand is a whole number
```

If you want the fractional answer, ask for one: use `decimal` (see [decimal](https://osysharp.com/reference/types/decimal/)) or `double` for the operand.
One fractional operand makes the **whole** expression fractional, wherever it appears in the chain.

```osy title="one fractional operand wins the whole expression" syntax
7m / 2m        // 3.5
(3 - 1) / 3m   // 0.666… — the decimal operand wins the expression
```

### Arithmetic fails at the edges rather than wrapping   {#overflow}

A `long` has a fixed width, so there are values arithmetic on it cannot produce. Running past the maximum **raises**,
naming the operands and the range — it does not wrap around to the minimum, and it does not quietly grow into a wider
type. Negating the minimum value raises for the same reason: its positive counterpart does not exist in 64 bits.

This is a deliberate difference from C#, which wraps by default. A wrapped total is not an obviously broken value like
a blank or an error — it is a plausible number of the wrong sign, and nothing downstream can tell it from a right one.
The same expression pushed down into the database raises too, so you get one answer wherever it runs.

If a value can legitimately grow past a `long`, say so in the type: use `decimal` (see [decimal](https://osysharp.com/reference/types/decimal/)) or `double`.

### The same answer everywhere   {#same-everywhere}

An Osy# expression means one thing. A `long` is exact **wherever the function runs** — server-side, or in-process in
the browser (see [execution side](https://osysharp.com/reference/function/execution-side/)) — including for values above 2^53, where a floating-point number would
silently round to a nearby value. Two ids that differ only in their last digit stay two different ids on both sides,
and a comparison that is true on one side is true on the other.

This matters more than it sounds. A rounded id is not an obviously broken value like a blank or an error; it is a
perfectly plausible id belonging to a different row. You do not need to know, or care, where a piece of code executes
in order to trust that the id you are holding is the one you were given.

## Examples       {#examples}

```osy title="an externally-issued id keeps every digit" test app=long-basics
entity Event {
  long ExternalId;
  [MaxLength(100)] string Name;
}
```

```osy title="paging by offset, in whole numbers" test app=long-basics
long PageOffset(long pageIndex, long pageSize) {
  return pageIndex * pageSize;
}
```

```osy title="ask for a fractional answer explicitly" test app=long-basics
decimal AveragePerItem(decimal total, long items) {
  return items == 0 ? 0m : total / items;
}
```

## See also       {#see-also}
- [decimal](https://osysharp.com/reference/types/decimal/) — exact base-10 arithmetic, for money and anything with a fractional part
- [execution side](https://osysharp.com/reference/function/execution-side/) — where a function runs; a `long` is exact on either side
