Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Function

Convert

Convert.ToInt(<value>) · Convert.ToInt64(<value>) · Convert.ToDecimal(<value>) · Convert.ToDouble(<value>) · Convert.ToString(<value>) · Convert.ToBool(<value>)

Explicit conversion between types — number to text, text to number, a Guid to its text form. Osy# will not convert silently where information could be lost, so you say it outright.

stable4 examples compiled by CIfunctionstdlibtypes

Summary#

Convert.* converts between types explicitly. Osy# does not convert silently where information could be lost — a decimal does not quietly become an int, dropping the pence — so where a conversion is what you want, you write it.

Signature#

Convert.ToInt(<value>)       // → int      (32-bit; truncates toward zero)
Convert.ToInt64(<value>)     // → long     (64-bit; truncates toward zero)
Convert.ToDecimal(<value>)   // → decimal
Convert.ToDouble(<value>)    // → double   (float64)
Convert.ToString(<value>)    // → string   (numbers, Guids, bools …)
Convert.ToBool(<value>)      // → bool

// C#'s own spellings work too — `Convert.ToInt32` IS `Convert.ToInt`, and `Convert.ToBoolean` IS
// `Convert.ToBool`. The same arms, so they behave identically; write whichever you reach for.
Convert.ToInt32(<value>)     // → int
Convert.ToBoolean(<value>)   // → bool

Description#

Convert.* or a cast?#

Both narrow, and they are not interchangeable. Between two NUMBERS, reach for the cast(int)x — which is the C# spelling and reads at a glance; see (int)x — casts. Reach for Convert.* when the input might not be a number at all, or when the output is text:

(int)amounta numeric conversion. Truncates toward zero, and fails if the value does not fit
Convert.ToInt(s)a parse. Reads an integer out of text, and answers 0 for text it cannot read
Convert.ToString(v)renders a value as text

The difference in the failure is the reason they are separate: a cast that cannot produce a value stops, while a parse of user-supplied text answers 0 and carries on — which is right for a form field and wrong for arithmetic.

This is where Osy# and C# differ, and it is the difference most likely to cost you. C#'s Convert.ToInt32("abc") throws FormatException. This answers 0 — no error, no null, a number that is wrong. So osy lint refuses Convert.To* over text at MUST tier (correctness-parse-that-answers-zero): say which you mean, and say it where the reader can see it.

if (decimal.TryParse(entered, out var cap)) { … } else { … }   // the C# spelling, and it compiles here

A numeric conversion — Convert.ToInt(Math.Floor(x)) — is untouched and behaves exactly as C# does. The lenient parse is still here and still useful; it just has to be asked for out loud.

Narrowing is explicit#

Widening happens on its own — an int is usable where a decimal is expected, because nothing is lost. Going the other way loses the fraction, so you must say so:

int WholeUnits(decimal amount) {
  return Convert.ToInt(Math.Floor(amount));   // decide the rounding, THEN narrow
}

Note the Math.Floor first. Convert.ToInt truncates toward zero, which is a rounding decision — and a rounding decision you make by accident is a rounding bug. Choose it deliberately: Math.Floor, Math.Ceiling, or Math.Round.

Convert.ToInt64 is the same narrowing to a 64-bit long instead of a 32-bit int — reach for it when the value can exceed ±2.1 billion (an id, a byte count, a running total of small amounts). It truncates toward zero exactly as Convert.ToInt does, so the same "round on purpose first" rule applies. See long for what a long is and why its range matters.

long TotalCents(decimal amount) {
  return Convert.ToInt64(Math.Round(amount * 100m));   // money as whole cents, 64-bit headroom
}

How do I get a double for non-money maths?#

Convert.ToDouble is the float64 front door. Reach for it when the value in hand is a decimal and the arithmetic downstream is not money — geometry, physics, a per-frame camera. Math.Round, Math.Floor, Math.Ceiling and Math.Truncate all answer a decimal when given one, so this is the conversion back:

double SnappedTo(decimal value, decimal step) {
  return Convert.ToDouble(Math.Round(value / step) * step);
}

It coerces like its siblings: text is parsed (0 for text it cannot read), null is 0, true is 1. Two things are true of a double that are not true of an int or a decimal, and both show up here:

Convert.ToDouble("NaN") · ("Infinity") · ("-Infinity")those are values a double HAS, so the text reads (any casing, optional sign)
Convert.ToDouble("1e400")+Infinity — an out-of-range magnitude is not a parse failure for this type (and "1e-400" is 0)

⚠ A double is not money. It cannot hold 0.1 exactly, so converting a price to one and back loses the pence silently — see Numeric types & literal suffixes for which type a value should have been in the first place.

What counts as a number#

Every Convert.To* reads text the same way, so a string that parses for one parses for all of them. The accepted shape is:

[white space] [+ or -] digits[,digits…][.digits] [e or E [+ or -] digits] [white space]
"1,000" · "12,34" · "100,"group separators are accepted, and their PLACEMENT is not checked
" 42 " · "\t42\n"a space, tab, newline, vertical tab, form feed or carriage return may pad it
"1e3" · "1.5e+2" · ".5" · "1."an exponent, a bare fraction and an empty fraction are all fine
",100" · "1.0,5"✗ a leading separator, or one in the fraction
"(5)" · "5-" · "¤5"✗ accounting parentheses, a trailing sign, a currency symbol
" 42" (non-breaking space)✗ a non-breaking space is not white space to a number
"0x1F" · "nope" · ""✗ — and the answer is 0, never an error and never NaN

The exact same grammar runs in the browser and inside a query the database executes, so a conversion answers the same thing wherever the expression happens to run. Convert.ToDouble reads three more forms, because a double has values the other types do not: "NaN", "Infinity" and "-Infinity", in any casing.

An integer conversion additionally refuses a non-zero fractionConvert.ToInt("42.9") is 0, while Convert.ToInt("42.0") is 42. If you want the number rounded, round it: Convert.ToInt(Math.Floor(x)).

How do I turn a number or a Guid into text?#

string Describe(int count, Guid id) {
  return "count=" + Convert.ToString(count) + " id=" + Convert.ToString(id);
}

For building a sentence out of several values, string interpolation reads better — $"count={count}" converts for you.

Money stays decimal#

Resist converting money to int or back. If you find yourself doing it to make arithmetic work, the accumulator is probably an int that should have been seeded 0m — see var.

See also#

Related

(int)x — casts

A C-style cast converts between the numeric types. It truncates toward zero, and it is checked — a value the target…

Numeric types & literal suffixes

The platform numeric types are int, long, decimal, and double. Literals follow C# exactly, suffixes (L, m, d) included:…

Typed locals

Locals can declare an explicit type instead of var; the declared type pins the binding. Literal initializers apply the…

String interpolation & format specifiers

Build a string from literal text and embedded expressions with $"…{expr}…". A hole may carry a .NET format specifier…

long

A 64-bit whole number, exact to its full range — ids, sequence numbers, row versions, byte offsets. It holds the same…