Cast operators
When two values are not of the same type, one will need to be casted to the other's type.
In Onyx, the cast
keyword is used. It takes on the following two forms described below.
Prefix form
main :: () {
x: i32 = 10;
y: f32 = 20.0f;
// Cast x to be a f32 so it can be added with y.
result := cast(f32) x + y;
println(result);
}
Here, a cast is needed to turn x
into a f32
so it can be added with y
.
This cast is in prefix form, which simply means it appears as a prefix to the thing being casted, similar to unary negation (-
).
Call form
BaseType :: struct {
name: str;
}
SubType :: struct {
use base: BaseType;
age: u32;
}
main :: () {
sub_value := SubType.{
age = 123
};
base_ptr: &BaseType = &sub_value;
age_value := cast(&SubType, base_ptr).age;
println(age_value);
}
In this contrived example, base_ptr
is casted to a &SubType
using the the call form of the cast operator.
This form is slightly nicer when you are going to immediately to follow the cast operation with a postfix operation.
In this case, .age
.
If this was written in prefix form, another set of parenthesis would be needed: (cast(&SubType) base_ptr).age
.
Auto casting
Sometimes, a cast necessary for the code to type check, but it is cumbersome to type the entire cast operation. Maybe the type is too long, or maybe the type is not even available because the package is not used. In these cases, the auto-cast operator can be used.
Auto-cast is written with a double-tilde (~~
).
This was chosen because there would be no purpose to performing a bitwise negation (~
) twice in a row.
To understand auto-cast, treat it like it was a cast(X)
, and the X
is automatically figured out by the compiler.
If the auto-cast is not possible, a compile-time error will be reported.
print_float :: (x: f32) {
printf("{}\n", x);
}
main :: () {
x := 10;
// Automatically cast x to an f32, since y is an f32.
y: f32 = ~~ x;
// Automatically cast x to an f32, since print_float expects an f32.
print_float(~~ x);
}
No "magic" casts
Onyx does not have "special" or "magic" casts between two completely unrelated types, such as strings and numbers.
Instead, conv.parse
and tprintf
should be used.
main :: () {
x := 10;
// Equivalent to `cast(str)` in some other languages
x_str := tprintf("{}", x);
// conv.parse parses a string into the type provided, and returns
// an optional of that type. So, a default must be provided using ??.
x_val := conv.parse(i32, x_str) ?? 0;
}