# Welcome to the FunC interactive cheat sheet!¶

This tutorial is still in work, any contribution is highly appreciated!
Language basics will be covered, more information can be found in the TON repo:

Basically, FunC is quite lightweight abstraction on top of TVM assembler, so if you read TVM spec you will likely get the core concepts very quickly.

## 🍬 Xeus-Fift specific features¶

### Include macro¶

In [1]:
#include "stdlib.fc"  ;; searches for file in the FUNCPATH and workdir

Out[1]:

### Main-wrapper¶

There can be three types of cell:

1. Includes
2. Function definitions (these functions can be accessed from all other cells)
3. Non-wrapped code

This non-wrapped code is taken as main entrypoint source and cannot be accessed from other cells.
Consider running a cell as a single invocation of a contract.

### Force return¶

In order to provide a truly interactive experience, xeus-fift inspects the last line of the cell and adds return and trailing semicolon if needed.

## Integers¶

### Basic operations¶

Underlying TVM type: signed 257-bit integers, representing integer numbers in the range -2^256 ... 2^256 ā 1

• Arithmetic + - * / %
• Bitwise & | << >>
• Boolean < <= > >= == !=
In [59]:
0x01 ^ 0x80  ;; xor

Out[59]:
129
In [60]:
8 <=> -4  ;; compare (1 if equal, -1 if less, 0 otherwise)

Out[60]:
1
In [210]:
~ 0xff + 0xff  ;; bitwise complement

Out[210]:
-1
In [214]:
min(-2, 0)

Out[214]:
-2
In [216]:
max(2, 3)

Out[216]:
3

### Division rounding rules¶

In [38]:
9 ~>> 2  ;; division by 2^n using nearest-integer rounding

Out[38]:
2
In [39]:
9 ^>> 2  ;; division by 2^n using ceiling rounding

Out[39]:
3

Rounding works similarly for integer division and modular division operators:
~/ ^/ ~% ^%

### Compound operators¶

In [40]:
11 /% 2  ;; extended mod division: computes both the quotient and the remainder

Out[40]:
5 1
In [65]:
divmod(11, 2)  ;; same effect

Out[65]:
5 1
In [66]:
moddiv(11, 2)  ;; change output order

Out[66]:
1 5
In [67]:
int x = 11;  ;; declaring variable of type int
x~divmod(2)  ;; non-const method (starting with ~)

Out[67]:
5 1
In [42]:
int x = 42;
x += 2

Out[42]:
44

Similar let-constructions can be made on top of with practically all integer operators:
-= *= /= %=
&= |= <<= >>= ^=
~>>= ^>>= ~/= ^/= ~%= ^%=

In [104]:
muldiv(3, 3, 2)  ;; equivalent of a * b / c

Out[104]:
4
In [105]:
muldivr(3, 3, 2)  ;; equivalent of a * b ~/ c

Out[105]:
5

### Constants¶

In [87]:
true

Out[87]:
-1
In [191]:
false

Out[191]:
0
In [43]:
~ false

{-
Btw, this is a multiline comment
-}

Out[43]:
-1

## Tuples¶

### FunC tuples¶

In [194]:
var t = (1, 2, 3);  ;; packing
t

Out[194]:
1 2 3
In [174]:
var (a, b, c) = (1, 2, 3);  ;; unpacking
b

Out[174]:
2
In [175]:
var (a, b) = (1, (2, 3));
b

Out[175]:
2 3
In [234]:
var (_, x, _) = (0xab, 0xcd, 0xef);  ;; one can use special operand _ for values that won't be used
x

Out[234]:
205

### TVM tuples¶

An ordered collection of up to 255 components, having arbitrary value types, possibly distinct.
May be used to represent nonpersistent values of arbitrary algebraic data types.

In [176]:
Nil  ;; 0-tuple

Out[176]:
[]

#### Pairs¶

In [177]:
pair(0xdead, 0xbeaf)

Out[177]:
[ 57005 48815 ]
In [208]:
second(pair(0xdead, 0xbeaf))

Out[208]:
48815
In [217]:
at(pair(0xdead, 0xbeaf), 0)  ;; universal helper for tuples

Out[217]:
57005
In [179]:
unpair(pair(0xdead, 0xbeaf))

Out[179]:
57005 48815

#### Triples¶

In [180]:
triple(1, 2, 3)

Out[180]:
[ 1 2 3 ]
In [202]:
third(triple(1, 2, 3))

Out[202]:
3
In [182]:
untriple(triple(1, 2, 3))

Out[182]:
1 2 3

#### 4-tuples¶

In [183]:
tuple4(-10, -20, -30, -40)

Out[183]:
[ -10 -20 -30 -40 ]
In [184]:
fourth(tuple4(-10, -20, -30, -40))

Out[184]:
-40
In [185]:
untuple4(tuple4(-10, -20, -30, -40))

Out[185]:
-10 -20 -30 -40

#### Lists¶

In [186]:
cons(1, cons(2, cons(3, Nil)))

Out[186]:
[ 1 [ 2 [ 3 [] ] ] ]
In [187]:
uncons(cons(1, cons(2, cons(3, Nil))))  ;; (head, tail)

Out[187]:
1 [ 2 [ 3 [] ] ]
In [188]:
car(cons(1, cons(2, cons(3, Nil))))  ;; head

Out[188]:
1
In [189]:
cdr(cons(1, cons(2, cons(3, Nil))))  ;; tail

Out[189]:
[ 2 [ 3 [] ] ]
In [190]:
list_next(cons(1, cons(2, cons(3, Nil))));  ;; (tail, head)

Out[190]:
[ 2 [ 3 [] ] ] 1

## Cells¶

A TVM cell consists of at most 1023 bits of data, and of at most four references to other cells.
All persistent data (including TVM code) in the TON Blockchain is represented as a collection of TVM cells.

The cell primitives are mostly either cell serialization primitives, which work with Builder s, or cell deserialization primitives, which work with Slices.

### Builders¶

A TVM cell builder, or builder for short, is an āincompleteā cell that supports fast operations of appending bitstrings and cell references at its end.
Builders are used for packing (or serializing) data from the top of the stack into new cells (e.g., before transferring them to persistent storage).

In [255]:
builder b = begin_cell()  ;; two descriptor bytes come first (read more in 3.1.4. Standard cell representation)

Out[255]:
BC{0000}
In [246]:
cell res = end_cell(begin_cell());

Out[246]:
C{96A296D224F285C67BEE93C30F8A309157F0DAA35DC5B87E410B78630A09CFC7}
In [302]:
begin_cell().end_cell()  ;; const method (dot is not a part of the function name)

Out[302]:
C{96A296D224F285C67BEE93C30F8A309157F0DAA35DC5B87E410B78630A09CFC7}
In [281]:
begin_cell().store_int(-0xFF, 32)  ;; we added a 32bit signed integer

Out[281]:
BC{0008ffffff01}
In [283]:
begin_cell().store_uint(-42, 32)

VM error: integer out of range
In [284]:
cell c1 = begin_cell().store_int(1, 8).end_cell();
begin_cell().store_ref(c1)  ;; first byte indicates that cell holds one reference

Out[284]:
BC{0100}

### Slices¶

A TVM cell slice, or slice for short, is a contiguous āsub-cellā of an existing cell, containing some of its bits of data and some of its references.
Essentially, a slice is a read-only view for a subcell of a cell.
Slices are used for unpacking data previously stored (or serialized) in a cell or a tree of cells.

In [307]:
cell c = begin_cell().store_int(0xfa, 16).end_cell();
c.begin_parse()

Out[307]:
CS{Cell{000400fa} bits: 0..16; refs: 0..0}
In [315]:
cell c = begin_cell().store_int(0xfa, 16).end_cell();
slice cs = c.begin_parse();
res

Out[315]:
250
In [334]:
cell c = begin_cell().store_uint(0xfa, 16).end_cell();
slice cs = c.begin_parse();
var (b1, b2) = (cs~load_uint(16), cs~load_uint(16))  ;; non-const method load reads and increases offset

VM error: cell underflow
In [430]:
cell c = begin_cell().store_int(0xfa, 16).end_cell();
slice cs = c.begin_parse();
cs.skip_bits(16).end_parse()  ;; ensure we read the entire cell with end_parse

Out[430]:

In [397]:
cell c = begin_cell().store_int(0xfa, 9).end_cell();
slice cs = c.begin_parse();
slice c8 = cs.skip_bits(1).first_bits(8);

Out[397]:
250
In [416]:
cell c1 = begin_cell().store_uint(1, 1).end_cell();
cell c2 = begin_cell().store_ref(c1).end_cell();

Out[416]:
1

### Hashmaps¶

Hashmaps, or dictionaries, are a specific data structure represented by a tree of cells.

In [294]:
new_dict()

Out[294]:
(null)
In [295]:
dict_empty?(new_dict())

Out[295]:
-1
In [21]:
slice test_slice(int byte) {
cell c = begin_cell().store_uint(byte, 8).end_cell();
return c.begin_parse();
}

Out[21]:

#### Set value¶

In [22]:
var d = new_dict();
d~udict_set(8, 1, test_slice(0xfa));
d.begin_parse()

Out[22]:
CS{Cell{0005a007ea} bits: 0..22; refs: 0..0}

#### Replace only if exists¶

In [37]:
var d = new_dict();
d~udict_set(8, 1, test_slice(0xfa));
var (d1, _) = udict_replace?(d, 8, 1, test_slice(0xfb));
d1.begin_parse()

Out[37]:
CS{Cell{0005a007ee} bits: 0..22; refs: 0..0}
In [38]:
var d = new_dict();
var (d1, found) = udict_replace?(d, 8, 1, test_slice(0xfa));
found

Out[38]:
0

#### Delete key¶

In [39]:
var d = new_dict();
d~udict_set(8, 1, test_slice(0xfa));
udict_delete?(d, 8, 1)  ;; returns new dict and boolean flag (found or not)

Out[39]:
(null) -1

#### Get value¶

In [36]:
var d = new_dict();
d~udict_set(8, 1, test_slice(0xfa));
udict_get?(d, 8, 1)  ;; returns slice and boolean flag (found or not)

Out[36]:
CS{Cell{0005a007ea} bits: 14..22; refs: 0..0} -1

## Functions¶

#### Return type¶

Can be any combination (nested funC tuples) of builtin types int tuple cell slice builder cont, special "hole" type _ (type is deduced from the return value), or void (empty tuple) ()

#### Modifiers¶

• impure - tells the compiler that function can modify passed arguments, and prevents function invocation pruning during the optimization;
• inline - works pretty the same as in C, tells the compiler to paste function body on every call occurence;
• inline_ref - in case of a simple inlining, an n-bit slice of the current continuation (cell) is converted to a new continuation (code and codepage), while inline_ref is when a cell reference is converted to a continuation and pushed onto the stack (more info in 4.2.3. Constant, or literal, continuations);
• method_id - declares a Get method (entrypoint) for the contract (that can be called along with the main, recv_internal and recv_external)

### ASM bindings¶

asm ( stack order of arguments -> stack order of return values ) "INSTRUCTION#0" "INSTRUCTION#1" ... "INSTRUCTION#N" Here is a comprehensive sample function from stdlib demonstrating all possible outcomes:

In [426]:
(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT";

Out[426]:

One can omit both or separate args/return stack ordering:

In [427]:
int dict_empty?(cell c) asm "DICTEMPTY";

Out[427]:

In [428]:
(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF";

Out[428]:

In [429]:
cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";

Out[429]:

### Generics¶

forall X0, X1, ... , Xn ->

In [425]:
forall X, Y -> tuple pair(X x, Y y) asm "PAIR";

Out[425]:

## Conditional statements¶

In [26]:
if (true) {
print(1);
} else {
print(2);
}

Out[26]:
1
In [28]:
ifnot (true) {
print(3);
} elseif (false) {
print(4);
} elseifnot (false) {
print(5);
}

Out[28]:
5

### Ternary operator¶

In [11]:
return 0 == 0 ? 1 : 2

Out[11]:
1

## Loops¶

In [17]:
int i = 10;
while (i > 0) {
print(i);
i -= 1;
}

Out[17]:
10 9 8 7 6 5 4 3 2 1
In [20]:
int i = 10;
do {
print(i);
i -= 1;
} until (i == 0)

Out[20]:
10 9 8 7 6 5 4 3 2 1
In [25]:
int i = 10;
repeat (5) { i *= 10; }
i

Out[25]:
1000000

## Exceptions¶

In [40]:
throw(31)

VM error: unknown code 31
In [38]:
throw_if(32, true);

VM error: unknown code 32
In [39]:
throw_unless(33, false)

VM error: unknown code 33