Type checks and casts
Tolk supports type conversions: either automatic or explicit via the as operator.
Automatic conversions
Assignable types can be provided explicitly:
fun takeOptInt(v: int?) {}
fun main() {
takeOptInt(100); // ok, `int` to `int?`
takeOptInt(null); // ok, `null` to `int?`
}Certain conversions are automatic:
inttointN.AliasForTandT(bidirectional).Cell<T>tocell.
fun autocast() {
var number: int32 = 100; // auto cast `int` to `int32`
}Non-assignable types cause a compilation error:
fun main() {
var number: int = true;
}
/// file.tolk:2:23: error: can not assign `bool` to variable of type `int`
/// hint: use `as` operator for UNSAFE casting: `<some_expr> as int`
///
/// // in function `main`
/// 2 | var number: int = true;
/// | ^^^^Smart casts
Once a variable is checked, the compiler narrows its type. For instance, if a variable could be null before the check, and the condition is confirmed to be true, the variable's type will not allow null in the true block anymore.
if (lastCell != null) {
// here lastCell is `cell`, not `cell?`
}Operator is for union types
Given a union type T1 | T2 | ..., the is operator performs a runtime type test, narrowing the type.
fun demo(v: int | Point | cell) {
if (v is Point) {
return v.x + v.y;
}
// v is `int | cell` here
}Non-null assertion with operator !
The ! operator bypasses the compiler's nullability check. It is similar to ! in TypeScript and !! in Kotlin.
fun doSmth(c: cell) {}
fun analyzeStorage(nCells: int, lastCell: cell?) {
// Say, according to the logic of this program,
// having non-zero number of `nCells` must mean
// that the `lastCell` is not `null`
if (nCells != 0) {
// Therefore, one can explicitly instruct
// the compiler to recognize that fact
doSmth(lastCell!);
}
}Unsafe cast with operator as
When non-trivial type transformations are required, the as operator overrides the restrictions by performing an unsafe type cast.
For instance, bool cannot be assigned directly to int. However, a direct cast using the as operator is valid since booleans are represented as TVM integers: true is -1, and false is 0.
var number: int = true as int; // -1The as operator skips type checking and performs no validation at runtime — it is purely a compile-time type cast.
This can lead to sudden errors and hidden bugs. For example, if one cast a slice as address and that slice did not hold a valid address, subsequent program becomes undefined and may error whenever that new "address" is used.
Not all transformations are possible. For example, 42 as cell is invalid. When a cast is inappropriate, the compiler indicates this in diagnostic messages.
The as operator converts types that share the same TVM representation:
addressis a TVM slice, sosomeAddr as sliceis valid.- Conversely,
someSlice as addressis valid.
- Conversely,
bitsN, whereNis between 1 and 1023, is a TVM slice, sosomeSlice as bitsNis valid.intN, whereNis between 1 and 257, is a TVM integer, sosomeInt64 as int32is valid.boolis as TVM integer, sosomeBool as intandsomeBool as int32result in -1 or 0.- Enums are TVM integers, so
someColor as intis valid.
Finally, the as operator cannot be applied to unions: v as Point is incorrect. Use the is operator and smart casts.
Last updated on