---
title: Compatibility with FunC
description: "Tact compiles to FunC and maps all its entities directly to various FunC and TL-B types."
---

Tact itself compiles to FunC and maps all its entities directly to various FunC and TL-B types.

## Convert types

[Primitive types](/book/types#primitive-types) in Tact are directly mapped to FunC ones.

All rules about copying variables are the same. One of the main differences is that there are no visible mutation operators in Tact, and most [`Slice{:tact}`](/book/cells#slices) operations mutate variables in place.

## Convert serialization

Serialization of [structs][struct] and [Messages](/book/structs-and-messages#messages) in Tact is automatic, unlike FunC, where you need to define serialization logic manually.

Tact's auto-layout algorithm is greedy. This means that it takes the next variable, calculates its size, and tries to fit it into the current cell. If it doesn't fit, it creates a new cell and continues. All inner structs for auto-layout are flattened before allocation.

All optional types are serialized as `Maybe` in TL-B, except for [`Address{:tact}`](/book/types#primitive-types).

There is no support for `Either` since it does not define which variant to pick during serialization in some cases.

### Examples

```tact
// _ value1:int257 = SomeValue;
struct SomeValue {
    value1: Int; // Default is 257 bits
}
```

```tact
// _ value1:int256 value2:uint32 = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as uint32;
}
```

```tact
// _ value1:bool value2:Maybe bool = SomeValue;
struct SomeValue {
    value1: Bool;
    value2: Bool?;
}
```

```tact
// _ cell:^cell = SomeValue;
struct SomeValue {
    cell: Cell; // Always stored as a reference
}
```

```tact
// _ cell:^slice = SomeValue;
struct SomeValue {
    cell: Slice; // Always stored as a reference
}
```

```tact
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256] = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as int256;
    value3: Int as int256;
    value4: Int as int256;
}
```

```tact
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256] flag:bool = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as int256;
    value3: Int as int256;
    flag: Bool; // Flag is written before value4 to prevent auto-layout from allocating it to the next cell
    value4: Int as int256;
}
```

```tact
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256 flag:bool] = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as int256;
    value3: Int as int256;
    value4: Int as int256;
    flag: Bool;
}
```

```tact
// _ value1:int256 value2:^TailString value3:int256 = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: String;
    value3: Int as int256;
}
```

## Convert received messages to `op` operations

Tact generates a unique `op` for every received typed message, but it can be overridden.

The following code in FunC:

```func
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
    ;; incoming message code...

    ;; Receive MessageWithGeneratedOp message
    if (op == 1180414602) {
        ;; code...
    }

    ;; Receive MessageWithOverwrittenOp message
    if (op == 291) {
        ;; code...
    }

}
```

Becomes this in Tact:

```tact
message MessageWithGeneratedOp {
    amount: Int as uint32;
}

message(0x123) MessageWithOverwrittenOp {
    amount: Int as uint32;
}

contract Contract {
    // Contract Body...

    receive(msg: MessageWithGeneratedOp) {
        // code...
    }

    receive(msg: MessageWithOverwrittenOp) {
        // code...
    }

}
```

## Convert `get`-methods

You can express everything except `list-style-lists` in Tact that would be compatible with FunC's `get`-methods.

### Primitive return type

If a `get`-method returns a primitive in FunC, you can implement it the same way in Tact.

The following code in FunC:

```func
int seqno() method_id {
    return 0;
}
```

Becomes this in Tact:

```tact
get fun seqno(): Int {
    return 0;
}
```

### Tensor return types

In FunC, there is a difference between the tensor types `(int, int){:func}` and `(int, (int)){:func}`, but for TVM there is no difference; they both represent a stack of two integers.

To convert the tensor returned from a FunC `get`-method, you need to define a [struct][struct] that has the same field types as the tensor and in the same order.

The following code in FunC:

```func
(int, slice, slice, cell) get_wallet_data() method_id {
    return ...;
}
```

Becomes this in Tact:

```tact
struct JettonWalletData {
    balance: Int;
    owner: Address;
    master: Address;
    walletCode: Cell;
}

contract JettonWallet {
    get fun get_wallet_data(): JettonWalletData {
        return ...;
    }
}
```

### Tuple return type

In FunC, if you are returning a tuple instead of a tensor, you need to follow the same process used for a tensor type but define the return type of a `get`-method as optional.

The following code in FunC:

```func
[int, int] get_contract_state() method_id {
    return ...;
}
```

Becomes this in Tact:

```tact
struct ContractState {
    valueA: Int;
    valueB: Int;
}

contract StatefulContract {
    get fun get_contract_state(): ContractState? {
        return ...;
    }
}
```

### Mixed tuple and tensor return types

When some of the returned values are tuples within a tensor, you need to define a struct as in the previous steps, and the tuple itself must be defined as a separate [struct][struct].

The following code in FunC:

```func
(int, [int, int]) get_contract_state() method_id {
    return ...;
}
```

Becomes this in Tact:

```tact
struct ContractStateInner {
    valueA: Int;
    valueB: Int;
}

struct ContractState {
    valueA: Int;
    valueB: ContractStateInner;
}

contract StatefulContract {
    get fun get_contract_state(): ContractState {
        return ...;
    }
}
```

### Arguments mapping

Conversion of arguments for `get` methods is straightforward. Each argument is mapped _as-is_ to a FunC argument, and each tuple is mapped to a [struct][struct].

The following FunC code:

```func
(int, [int, int]) get_contract_state(int arg1, [int,int] arg2) method_id {
    return ...;
}
```

becomes this in Tact:

```tact
struct ContractStateArg2 {
    valueA: Int;
    valueB: Int;
}

struct ContractStateInner {
    valueA: Int;
    valueB: Int;
}

struct ContractState {
    valueA: Int;
    valueB: ContractStateInner;
}

contract StatefulContract {
    get fun get_contract_state(arg1: Int, arg2: ContractStateArg2): ContractState {
        return ContractState {
            valueA: arg1,
            valueB: ContractStateInner {
                valueA: arg2.valueA,
                valueB: arg2.valueB, // trailing comma is allowed
            }, // trailing comma is allowed
        };
    }
}
```

[struct]: /book/structs-and-messages#structs
