Universal createMessage
In FunC, you had to compose message cells manually and regularly face code like:
cell m = begin_cell()
    .store_uint(0x18, 6)
    .store_slice(sender_address)
    .store_coins(50000000)
    .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
    .store_uint(0x178d4519, 32)
    .store_uint(query_id, 64)
    ...
    .end_cell();
send_raw_message(m, 0);
In Tolk, you use a high-level function — and it's even more gas-effective:
val reply = createMessage({
    bounce: true,
    value: ton("0.05"),
    dest: senderAddress,
    body: RequestedInfo { ... }
});
reply.send(SEND_MODE_REGULAR);
Key features of createMessage
- Supports extra currencies
- Supports stateInit(code+data) with automatic address computation
- Supports different WorkChains
- Supports sharding (formerly splitDepth)
- Integrated with auto-serialization of body
- Automatically detects body ref or not
- More efficient than handwritten code
The concept is based on union types
There is a huge variety of interacting between contracts. When you explore FunC implementations, you notice that:
- sometimes, you "send to an address (slice)"
- ... but sometimes, you "build the address (builder) manually"
- sometimes, you compose StateInitfrom code+data
- ... but sometimes, you already have StateInitas a ready cell
- sometimes, you send a message to basechain
- ... but sometimes, you have the MY_WORKCHAINconstant and use it everywhere
- sometimes, you just attach tons (msg value)
- ... but sometimes, you also need extra currencies
- etc.
How can we describe such a vast variety of options? The solution is union types!
Let's start exploring this idea by looking at how extra currencies are supported.
Extra currencies: union
When you don't need them, you just attach msg value as tons:
value: someTonAmount
When you need them, you attach tons AND extra currencies dict:
value: (someTonAmount, extraDict)
How does it work? Because the field value is a union:
// how it is declared in stdlib
type ExtraCurrenciesDict = dict;
struct CreateMessageOptions<TBody> {
    ...
    /// message value: attached tons (or tons + extra currencies)
    value: coins | (coins, ExtraCurrenciesDict)
That's it! You just attach tons OR tons with extra, and the compiler takes care of composing this into a cell.