fun f(<params>)— a functionfun <receiver>.f(<params>)— a method:fun <receiver>.f(self, ...)— an instance methodfun <receiver>.f(...)— a static method (noself)
Types for parameters are required
The return type is auto-inferred if omitted
Either specify return type manually:return statements, similar to TypeScript:
Default values for parameters
Default values are placed after the type, allowing constant expressions:Methods: for any type, including structures
A method is declared as an extension function, similar to Kotlin. If the first parameter isself, it’s an instance method. Otherwise, it’s a static method.
obj.method(), whereas static methods — on a type:
fun cell.hash(self), etc.
The type of self is determined by the receiver.
All parameters after should have their types set.
The return type is inferred if omitted.
self is immutable by default
To allow modifications, declare mutate self explicitly.
For details, see mutability.
return self makes a chainable method
To make a method chainable, declare it as fun (...): self.
For instance, all methods for builder return self,
which allows b.storeXXX().storeXXX():
Small functions are automatically inlined
Create one-liner methods without any worries. The compiler automatically inlines them in-place, targeting zero overhead. For example, this program@attributes
A function or method may be preceded by one or several attributes:@inline— Forces a function to be inlined in-place. Typically unnecessary, as the compiler performs inlining automatically.@inline_ref— Turns on a special version of inlining: its body will be embedded as a child cell reference in the resulting bytecode.@noinline— Disables inlining for a function. For example, if it’s a “slow path”.@method_id(<number>)— Low-level annotation to manually override TVM method_id.@pure— Indicates that a function does not modify global state (including TVM one). If its result is unused, a call could be deleted. Typically used in assembler functions.@deprecated— A function is not recommended for use and exists only for backwards compatibility.@custom(<anything>)— A custom expression, not analyzed by the compiler.
Assembler functions
Tolk supports declaring low-level assembler functions with embedded Fift code:Anonymous functions (lambdas)
Tolk supports first-class functions: they can be passed as callbacks. Both named functions and function expressions may be referenced:Generic functions
A function declared asfun f<T>(...) is a generic one. T is called a “type parameter”.
f<...>(args):
fun f<T1, T2 = int>, but they cannot reference one another currently.
Although type parameters are usually inferred from the arguments, there are edge cases where T cannot be inferred because it does not depend on them.
For example, tuples. A tuple may have anything inside it, that’s why invoking tuple.get lacks without T:
T must be specified explicitly because this is not a call:
Generic methods
Declaring a method for a generic type does not differ from declaring any other method. The compiler treats unknown symbols as type parameters while parsing the receiver:Methods for “any receiver”
Any unknown symbol (typicallyT) may be used to define a method applicable to any type:
Partial specialization of generic methods
Specializing generic methods allows some logic to work differently for predefined types or patterns. Consider the following example. Suppose, there is an iterator over a tuple of slices, each slice contains encodedT.
TupleIterator<int32> or TupleIterator<Point>, next() will decode the next slice and return it.
But additional requirements are:
TupleIterator<slice>should just returndata[i]without callingfromSlice()TupleIterator<Cell<T>>should return notCell<T>but unpack a cell and returnT
map<K, V>, but
- if
V = K, provide a different implementation - if
Vis another map, modify the behavior