Tolk v0.9 introduces nullable types:
int?, cell?, and T?, bringing null safety to your code. The compiler prevents using nullable values without checks, but thanks to smart casts, this feels smooth and natural.β Notable changes in Tolk v0.9:
1. Nullable types
int?, cell?, etc.; null safety2. Standard library updated to reflect nullability
3. Smart casts, like in TypeScript in Kotlin
4. Operator
! (non-null assertion)5. Code after
throw is treated unreachable6. The
never typePR on GitHub with detailed info.
β Nullable types and null safety
In FunC,
null was implicitly assignable to any primitive type β too permissive. A variable declared as int could still hold null at runtime, leading to TVM exceptions if used incorrectly.Tolk now forces you to explicitly mark nullable values. This aligns with TypeScript
T | null and Kotlin, preventing unintended null usage.
value = x > 0 ? 1 : null; // int?
value + 5; // error
s.storeInt(value); // error
if (value != null) {
value + 5; // ok
s.storeInt(value); // ok
}
* any type can be nullable:
cell?, [int, slice]?, (int, cell)?* no more unexpected TVM exceptions due to null
* at runtime,
int? and cell? occupy just one stack slot β zero overheadβ Smart casts (via control flow graph)
Once a nullable value is checked, the compiler automatically refines its type:
if (lastCell != null) {
// here lastCell is `cell`, not `cell?`
}
or:
if (lastCell == null || prevCell == null) {
return;
}
// both lastCell and prevCell are `cell`
or:
var x: int? = ...;
if (x == null) {
x = random();
}
// here x is `int`
Smart casts ensure code is safe while remaining gas-efficient (compile-time only).
β Operator `!` (non-null assertion)
If you know a value can't be null, use the
! operator to bypass nullability checks:
// this key 100% exists, make it `cell`, not `cell?`
validators = getBlockchainConfigParam(16)!;
It's useful for low-level TVM functions (dicts, particularly), when you have guarantees outside the code. Use with care!
β The `never` type
Now, you can declare "always-throwing functions":
fun alwaysThrows(): never {
throw 123;
}
fun f() {
...
alwaysThrows(); // no return needed after this
}
never also occurs implicitly when a condition is impossible:
var v = 0;
// compiler warning: `int` can never be `null`
if (v == null) {
// v is `never`
}
... this is just the beginning! Nullable tensors, tricky smart casts, and low-level null safety details β all explained in the PR.
π³ Null safety is smooth, intuitive, and enforced at compile time β no runtime cost, no extra gas, just safer code.