Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

chore: Split composite-types into standalone pages #137

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions pages/book/_meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@ export default {
},
types: 'Type system overview',
integers: 'Integers',
maps: 'Maps',
'structs-and-messages': 'Structs and Messages',
optionals: 'Optionals',
// <- a place for https://github.com/tact-lang/tact-docs/issues/115 + brief info on comments
'-- 2': {
type: 'separator',
title: 'Expressiveness',
},
operators: 'Operators',
expressions: 'Expressions',
statements: 'Statements',
constants: 'Constants',
functions: 'Functions',
'composite-types': 'Composite types',
// <- a place for https://github.com/tact-lang/tact-docs/issues/115
'-- 2': {
'-- 3': {
type: 'separator',
title: 'Communication',
},
Expand All @@ -29,7 +35,7 @@ export default {
lifecycle: 'Message lifecycle',
send: 'Sending messages',
'message-mode': 'Message mode',
'-- 3': {
'-- 4': {
type: 'separator',
title: 'Going places',
},
Expand Down
2 changes: 1 addition & 1 deletion pages/book/cookbook.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ if (first == null) {
<Callout>

**Useful links:**\
[`map<k, v>{:tact}` type in the Book](/book/types#maps)
[`map<k, v>{:tact}` type in the Book](/book/maps)

</Callout>

Expand Down
10 changes: 5 additions & 5 deletions pages/book/expressions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ if (var != null) {
}
```

Read more about working with `null{:tact}` in the dedicated chapter: [Optionals](/book/composite-types#optionals).
Read more about working with `null{:tact}` on the dedicated page: [Optionals](/book/optionals).

## Identifiers

An identifier is a sequence of characters in the code that _identifies_ a [variable](/book/statements#let), [constant](/book/constants), [map](/book/types#maps) and a [function](/book/functions), as well as a [Struct][s], [Message][m], [contract](/book/types#contract), [trait](/book/types#trait), or their fields and methods. Identifiers are case-sensitive and not quoted.
An identifier is a sequence of characters in the code that _identifies_ a [variable](/book/statements#let), [constant](/book/constants), [map](/book/maps) and a [function](/book/functions), as well as a [Struct][s], [Message][m], [contract](/book/types#contract), [trait](/book/types#trait), or their fields and methods. Identifiers are case-sensitive and not quoted.

In Tact, identifiers can contain latin lowercase letters (`a-z`), latin uppercase letters (`A-Z`), underscores (`_`) and digits ($\mathrm{0 - 9}$), but may not start with a digit. An identifier differs from a [string](#string-literals) in that a string is data, while an identifier is part of the code.

Note, that when identifiers for [primitive types][p] start with an uppercase letter. Used-defined [composite types](/book/composite-types), such as [Structs][s] and [Messages][m] also must be capitalized.
Note, that when identifiers for [primitive types][p] start with an uppercase letter. Used-defined [composite types](/book/types#composite-types), such as [Structs][s] and [Messages][m] also must be capitalized.

## Instantiation

Expand Down Expand Up @@ -189,5 +189,5 @@ Field | Type | Description
`data` | [`Cell{:tact}`][p] | initial data of the contract (arguments of `init(){:tact}` function of the contract)

[p]: /book/types#primitive-types
[s]: /book/composite-types#structs
[m]: /book/composite-types#messages
[s]: /book/structs-and-messages#structs
[m]: /book/structs-and-messages#messages
8 changes: 4 additions & 4 deletions pages/book/func.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ All rules about copying variables are the same. One of the big differences is th

## Convert serialization

Serialization of [Structs](/book/composite-types#structs) and [Messages](/book/composite-types#messages) in Tact is automatic, unlike FunC where you need to define serialization logic manually.
Serialization of [Structs](/book/structs-and-messages#structs) 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 a current cell. If it doesn't fit, it creates a new cell and continues. All inner structs for auto-layout are flattened before allocation.

Expand Down Expand Up @@ -174,7 +174,7 @@ get fun seqno(): Int {

In FunC there is a difference between tensor type `(int, int){:func}` and `(int, (int)){:func}`, but for TVM there are no differences, they all represent a stack of two integers.

To convert the tensor that returned from a FunC `get`-method, you need to define a [Struct](/book/composite-types#structs) that has the same field types as the tensor and in the same order.
To convert the tensor that returned from a FunC `get`-method, you need to define a [Struct](/book/structs-and-messages#structs) that has the same field types as the tensor and in the same order.

The following code in FunC:

Expand Down Expand Up @@ -230,7 +230,7 @@ contract StatefulContract {

### Mixed tuple and tensor return types

When some of the tensors are a tuple, you need to define a struct as in previous steps and the tuple one must be defined as a separate [Struct](/book/composite-types#structs).
When some of the tensors are a tuple, you need to define a struct as in previous steps and the tuple one must be defined as a separate [Struct](/book/structs-and-messages#structs).

The following code in FunC:

Expand Down Expand Up @@ -262,7 +262,7 @@ contract StatefulContract {

### Arguments mapping

Conversion of `get`-methods arguments is straightforward. Each argument is mapped _as-is_ to FunC one, and each tuple is mapped to a [Struct](/book/composite-types#structs).
Conversion of `get`-methods arguments is straightforward. Each argument is mapped _as-is_ to FunC one, and each tuple is mapped to a [Struct](/book/structs-and-messages#structs).

The following code in FunC:

Expand Down
2 changes: 1 addition & 1 deletion pages/book/integers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ contract SerializationExample {
}
```

Integer serialization is also available for the fields of [Structs](/book/composite-types#structs) and [Messages](/book/composite-types#structs), as well as in key/value types of [maps](/book/types#maps):
Integer serialization is also available for the fields of [Structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages), as well as in key/value types of [maps](/book/maps):

```tact
struct StSerialization {
Expand Down
43 changes: 43 additions & 0 deletions pages/book/maps.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Maps

import { Callout } from 'nextra/components'

The type `map<k, v>{:tact}` is used as a way to associate keys of type `k` with corresponding values of type `v`.

Possible key types:

* [`Int{:tact}`][ints]
* `Address{:tact}`

Possible value types:

* [`Int{:tact}`][ints]
* [`Bool{:tact}`](/book/types#booleans)
* `Cell{:tact}`
* `Address{:tact}`
* [Struct](/book/structs-and-messages#structs)
* [Message](/book/structs-and-messages#messages)

For example, `map<Int, Int>{:tact}` uses [`Int{:tact}`][ints] type for its keys and values:

```tact
struct IntToInt {
counters: map<Int, Int>;
}
```

Additionally, maps allow [integer serialization](/book/integers#serialization-types) of their keys, values or both to [preserve space and reduce storage costs](/book/integers#serialization):

```tact
struct SerializedMapInside {
countersButCompact: map<Int as uint8, Int as uint8>;
}
```

<Callout>

Read about other serialization options: [Compatibility with FunC](/book/func#convert-serialization)

</Callout>

[ints]: /book/integers
12 changes: 6 additions & 6 deletions pages/book/operators.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This page lists all the operators in Tact in decreasing order of their [preceden

<Callout>

Note, that there are no implicit type conversions in Tact, so operators can't be used to, say, add values of different type or compare them in terms of equality without explicitly casting to the same type. That's done with certain functions from the standard library. See [`Int.toString(){:tact}`](https://docs.tact-lang.org/language/ref/strings#inttostring) for an example of such function.
Note, that there are no implicit type conversions in Tact, so operators can't be used to, say, add values of different type or compare them in terms of equality without explicitly casting to the same type. That's done with certain functions from the standard library. See [`Int.toString(){:tact}`](/language/ref/strings#inttostring) for an example of such function.

</Callout>

Expand Down Expand Up @@ -51,7 +51,7 @@ Unary double-exclamation mark (_non-null assertion_) operator `!!{:tact}` is a p

<Callout>

Read more about optional variables and fields here: [Book→Composite Types](https://docs.tact-lang.org/book/composite-types#optionals)
Read more about optional variables and fields here: [Optionals](/book/optionals)

</Callout>

Expand Down Expand Up @@ -135,7 +135,7 @@ two % 1; // 1
-1 % -5; // -1
```

The simplest way to avoid confusion between the two is to prefer using positive values via [`abs(x: Int){:tact}`](https://docs.tact-lang.org/language/ref/math#abs):
The simplest way to avoid confusion between the two is to prefer using positive values via [`abs(x: Int){:tact}`](/language/ref/math#abs):

```tact
abs(-1) % abs(-5); // 1
Expand Down Expand Up @@ -297,7 +297,7 @@ Can be applied to values of following types:
* [`Cell{:tact}`](/book/types#primitive-types), implicitly compares via `.hash(){:tact}`
* [`Slice{:tact}`](/book/types#primitive-types), implicitly compares via `.hash(){:tact}`
* [`String{:tact}`](/book/types#primitive-types)
* [`map<k, v>{:tact}`](/book/types#maps), but only if their key and value types are identical
* [`map<k, v>{:tact}`](/book/maps), but only if their key and value types are identical

```tact
// Int:
Expand Down Expand Up @@ -344,7 +344,7 @@ Can be applied to values of following types:
* [`Cell{:tact}`](/book/types#primitive-types), implicitly compares via `.hash(){:tact}`
* [`Slice{:tact}`](/book/types#primitive-types), implicitly compares via `.hash(){:tact}`
* [`String{:tact}`](/book/types#primitive-types)
* [`map<k, v>{:tact}`](/book/types#maps), but only if their key and value types are identical
* [`map<k, v>{:tact}`](/book/maps), but only if their key and value types are identical

```tact
// Int:
Expand Down Expand Up @@ -480,7 +480,7 @@ true ? (false ? 1 : 2) : 3; // 2

## Assignment, `=` [#assignment]

Assignment operator `={:tact}` is used to assign a value to a variable, or to a property of a [Message](/book/composite-types#messages) or a [Struct](/book/composite-types#structs). The assignent is a statement and it doesn't return a value.
Assignment operator `={:tact}` is used to assign a value to a variable, or to a property of a [Message](/book/structs-and-messages#messages) or a [Struct](/book/structs-and-messages#structs). The assignment is a statement and it doesn't return a value.

```tact
let someVar: Int = 5; // assignment operator = is used here...
Expand Down
42 changes: 42 additions & 0 deletions pages/book/optionals.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Optionals

import { Callout } from 'nextra/components'

As it was mentioned in [type system overview](/book/types#optionals), all [primitive types](/book/types#primitive-types), [Structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages) could be nullable. That is, they don't necessarily hold any value, aside from `null{:tact}` — a special value, which represents the intentional absence of any other value.

[Variables](/book/statements#let) or fields of [Structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages) that can hold `null{:tact}` are called "optionals". They're useful to reduce state size when the variable isn't necesserily used.

You can make any variable or a field an optional by adding a question mark (`?{:tact}`) after its type declaration. The only exceptions are [`map<k, v>{:tact}`](/book/maps) and [`bounced<Msg>{:tact}`](/book/bounced#bounced-messages-in-tact), where you can't make them, inner key/value type (in case of a map) or the inner [Message](/book/structs-and-messages#messages) (in case of a bounced) optional.

Optional variables or optional fields that are not defined hold the `null{:tact}` value by default. You cannot access them without checking for `null{:tact}` first. But if you're certain they are not `null{:tact}` at a given moment, use the [non-null assertion operator `!!{:tact}`](/book/operators#unary-non-null-assert) to access their value.

Trying to access the value of an optional variable or an optional field without using [`!!{:tact}`](/book/operators#unary-non-null-assert) or without checking for `null{:tact}` beforehand will result in a compilation error.

Example of optionals:

```tact
struct StOpt {
opt: Int?; // Int or null
}

message MsOpt {
opt: StOpt?; // Notice, how the struct StOpt is used in this definition
}

contract Optionals {
opt: Int?;
address: Address?;

init(opt: Int?) { // optionals as parameters
self.opt = opt;
self.address = null; // explicit null value
}

receive(msg: MsOpt) {
let opt: Int? = 12; // defining a new variable
if (self.opt != null) { // explicit check
self.opt = opt!!; // using !! as we know that opt value isn't null
}
}
}
```
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# Composite types
# Structs and Messages

import { Callout } from 'nextra/components'

Tact supports a number of [primitive data types](/book/types#primitive-types) that are tailored for smart contract use. However, using individual means of storage often becomes cumbersome, so there are two main ways to combine multiple primitives together: [Structs](#structs) and [Messages](#messages).

Note, while Traits and Contracts are also considered a part of the Tacts type system, one can't pass them around like [Structs](#structs) or [Messages](#messages). Instead, one can obtain the initial state of the given Contract by using the [`initOf{:tact}`](/book/expressions#initof) expression.
Tact supports a number of [primitive data types](/book/types#primitive-types) that are tailored for smart contract use. However, using individual means of storage often becomes cumbersome, so there are [Structs](#structs) and [Messages](#messages) which allow combining types together.

<Callout type="warning" emoji="⚠️">

**Warning**: Currently circular types are **not** possible. This means that struct/message **A** can't have a field of a struct/message **B** that has a field of the struct/message **A**.
**Warning**: Currently circular types are **not** possible. This means that Struct/Message **A** can't have a field of a Struct/Message **B** that has a field of the Struct/Message **A**.

Therefore, the following code **won't** compile:

Expand Down Expand Up @@ -105,44 +103,3 @@ This is useful for cases where you want to handle certain opcodes (operation cod
[Jetton Standard in Tact on Tact-by-Example](https://tact-by-example.org/07-jetton-standard)

</Callout>

## Optionals

As it was mentioned in [type system overview](/book/types), most [primitive types](/book/types#primitive-types), [Structs](#structs) and [Messages](#messages) could be nullable. That is, they don't necessarily hold any value, aside from `null{:tact}` — a special value, which represents the intentional absence of any other value.

[Variables](/book/statements#variable-declaration) or fields of [Structs](#structs) and [Messages](#messages) that can hold `null{:tact}` are called "optionals". They're useful to reduce state size when the variable isn't necesserily used.

You can make any variable or a field an optional by adding a question mark (`?{:tact}`) after its type declaration. The only exceptions are [`map<>{:tact}`](/book/types#maps) and [`bounced<>{:tact}`](/book/bounced#bounced-messages-in-tact), where you can't make them, inner key/value type (in case of a map) or the inner [Message](#messages) (in case of a bounced) optional.

Optional variables or optional fields that are not defined hold the `null{:tact}` value by default. You cannot access them without checking for `null{:tact}` first. But if you're certain they are not `null{:tact}` at a given moment, use the non-null assertion operator (`!!{:tact}`) to access their value.

Trying to access the value of an optional variable or an optional field without using `!!{:tact}` or without checking for `null{:tact}` beforehand will result in a compilation error.

Example of optionals:

```tact
struct StOpt {
opt: Int?; // Int or null
}

message MsOpt {
opt: StOpt?; // Notice, how the struct StOpt is used in this definition
}

contract Optionals {
opt: Int?;
address: Address?;

init(opt: Int?) { // optionals as parameters
self.opt = opt;
self.address = null; // explicit null value
}

receive(msg: MsOpt) {
let opt: Int? = 12; // defining a new variable
if (self.opt != null) { // explicit check
self.opt = opt!!; // using !! as we know that opt value isn't null
}
}
}
```
Loading
Loading