# (int)x — casts

> A C-style cast converts between the numeric types. It truncates toward zero, and it is checked — a value the target type cannot hold fails loudly rather than wrapping to a wrong number.

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

## Summary        {#summary}
A cast converts a value from one numeric type to another: `(int)x`, `(long)x`, `(decimal)x`, `(double)x`. It
truncates toward zero, exactly as C# does, and it is **checked** — a value the target type cannot hold fails with a
message naming the value and the range, rather than silently wrapping.

## Signature      {#signature}
```osy syntax
(int)<value>       // → int      32-bit; truncates toward zero
(long)<value>      // → long     64-bit; truncates toward zero
(decimal)<value>   // → decimal  exact base-10
(double)<value>    // → double   IEEE 754
```

## Description    {#description}

### When do I need a cast?   {#purpose}
Widening happens on its own: an `int` is usable where a `double` or a `decimal` is expected, because nothing is
lost. **Narrowing never happens on its own** — dropping a fraction is a decision, so you write it down. A cast is
how you write it.

The everyday case is a value that is fractional while it is being computed and whole once it is used: a grid cell
from a position, a page number from a ratio, a pixel column from an angle.

```osy title="a fractional value, used as a whole one" test app=function-cast
int CellOf(double position, double cellSize) {
  return (int)(position / cellSize);      // the division is fractional; the cell index is not
}
```

### It truncates toward ZERO   {#truncation}
`(int)2.7` is `2` and `(int)-2.7` is `-2` — toward zero, not toward negative infinity. That matters for any value
that can go negative (a camera coordinate, a delta, a temperature), where truncation and `Math.Floor` disagree:

| value | `(int)v` | `Math.Floor(v)` |
|---|---|---|
| `2.7` | `2` | `2` |
| `-2.7` | `-2` | `-3` |

If you want floor behaviour, say so — `(int)Math.Floor(v)` — and if you want a different rounding, choose it with
[Math.Abs, Math.Sign, Math.Min, Math.Max, Math.Clamp, Math.Truncate, Math.Pow, Math.Sqrt, Math.Sin, Math.Cos, Math.Tan](https://osysharp.com/reference/function/math/) before you narrow. A cast makes no rounding decision for you beyond dropping the fraction.

### What happens when the value does not fit?   {#checked}
C# is *unchecked* by default: `(int)3000000000L` is `-1294967296` there, and `(int)1e20` is formally undefined.
Both are silent wrong answers, so Osy# does not reproduce them. A value outside the target's range **fails**:

```text
cannot cast the value 3000000000 to 'int' — it is outside the range of 'int'
(-2147483648 … 2147483647). An Osy# cast is checked: it fails rather than wrapping to a wrong number.
```

The C# spelling that means the same thing is `checked((int)x)`. `NaN` and `±Infinity` have no integer or decimal
value, so casting one of them to `int`, `long` or `decimal` fails too; both are ordinary values for `(double)`.

The rule holds wherever the expression runs — in a function, in a UI action, in a frame body, and in a query
pushed down to the database.

### A cast does not parse, and it does not format   {#not}
A cast converts **numbers**. It does not parse, and it does not format:

| you wrote | what to write instead |
|---|---|
| `(int)"42"` | `Convert.ToInt(s)` — a parse, which can fail; see [Convert](https://osysharp.com/reference/function/convert/) |
| `(string)total` | `total.ToString()` |
| `(bool)count` | `count != 0` |

Each of those is a compile error naming the alternative. There is no cast to an entity, a `class` or an `enum`
either — casting is the numeric conversion operator, nothing more.

### Casting to `decimal` and `double`   {#widening-casts}
Both directions are legal and both are sometimes what you mean:

- `(decimal)aDouble` takes C#'s conversion — 15 significant digits — so it is the deliberate move from *fast* to
  *exact*. Reach for it at the point money enters the calculation.
- `(double)aDecimal` goes the other way, for geometry and physics, where agreeing with the browser's arithmetic
  matters more than base-10 exactness.
- A cast to the type a value already has (`(double)aDouble`) is legal and does nothing.

```osy title="both directions, on purpose" test app=function-cast
decimal Price(double raw) { return (decimal)raw; }             // fast → exact
double Ratio(decimal part, decimal whole) {
  return (double)part / (double)whole;                          // exact → fast
}
long Micros(decimal amount) { return (long)(amount * 1000000m); }
```

### Does `(int)a * b` cast `a`, or the product?   {#precedence}
A cast binds tighter than arithmetic, exactly as in C#: `(int)a * b` is `((int)a) * b`. Parenthesise the
expression when you mean to convert the whole thing — `(int)(a * b)`.

`(x) - y` is still a subtraction. Only the four type keywords above introduce a cast, so a parenthesised name never
becomes one by accident.

## Examples       {#examples}
```osy title="the whole surface" test app=function-cast
int Truncated() { return (int)-2.7d; }                  // -2 — toward zero
int Floored() { return (int)Math.Floor(-2.7d); }        // -3 — the other rounding, said out loud
long Big(double v) { return (long)v; }
double AsDouble(int n) { return (double)n / 2d; }       // 2.5, not 2 — the cast makes it float division
int Column(double angle, double width) {
  return (int)(angle * width);                          // parenthesised: the product is narrowed
}
```

## See also       {#see-also}
- [Convert](https://osysharp.com/reference/function/convert/) — `Convert.*`, for converting *text* to a number (a parse, which can fail differently)
- [Math.Abs, Math.Sign, Math.Min, Math.Max, Math.Clamp, Math.Truncate, Math.Pow, Math.Sqrt, Math.Sin, Math.Cos, Math.Tan](https://osysharp.com/reference/function/math/) — choose the rounding before you narrow
- [Numeric types & literal suffixes](https://osysharp.com/reference/function/numeric-literals/) — the four numeric types and their literal suffixes
- [long](https://osysharp.com/reference/types/long/) — what a `long` is, and when 32 bits is not enough
