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#
(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 754Description#
When do I need a cast?#
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.
int CellOf(double position, double cellSize) {
return (int)(position / cellSize); // the division is fractional; the cell index is not
}It truncates toward ZERO#
(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 before you narrow. A cast makes no rounding decision for you beyond dropping the fraction.
What happens when the value does not fit?#
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:
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#
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 |
(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#
Both directions are legal and both are sometimes what you mean:
(decimal)aDoubletakes 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)aDecimalgoes 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.
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?#
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#
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#
- 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 — choose the rounding before you narrow
- Numeric types & literal suffixes — the four numeric types and their literal suffixes
- long — what a
longis, and when 32 bits is not enough