Skip to content

Commit

Permalink
docs: illustrate workaround for nested maps (#1593)
Browse files Browse the repository at this point in the history
  • Loading branch information
novusnota authored Jan 29, 2025
1 parent 15ff445 commit 596d2ce
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
1 change: 1 addition & 0 deletions dev-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Documented `BaseTrait` and methods in stdlib code: PR [#1296](https://github.com/tact-lang/tact/pull/1296)
- Document how storage variables get updated in relation to the `init()` function: PR [#1311](https://github.com/tact-lang/tact/pull/1311)
- Document compiler upgrades in Blueprint and other Tact projects: PR [#1560](https://github.com/tact-lang/tact/pull/1560)
- Illustrate how nested maps can be created: PR [#1593](https://github.com/tact-lang/tact/pull/1593)

### Release contributors

Expand Down
37 changes: 35 additions & 2 deletions docs/src/content/docs/book/maps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,38 @@ struct IntToInt {
}
```

Since maps can use any given [Struct][struct] as their [value types](#allowed-types), the nested maps can be created via helper structures like this:

```tact
import "@stdlib/deploy";
// A `map<Address, Int>` packed into the `AllowanceMap` structure
struct AllowanceMap { unbox: map<Address, Int> }
contract NestedMaps with Deployable {
get fun test(): Int {
// An outer map `map<Address, AllowanceMap>`,
// with `AllowanceMap` Structs as values,
// each containing maps of type `map<Address, Int>`
let allowances: map<Address, AllowanceMap> = emptyMap();
// An inner map in the `unbox` field of the `AllowanceMap` Struct
let allowance = AllowanceMap{ unbox: emptyMap() };
// Setting the inner map entry
allowance.unbox.set(myAddress(), 42);
// Setting the outer map entry
allowances.set(myAddress(), allowance);
// Produces 42
return allowances.get(myAddress())!!.unbox.get(myAddress())!!;
}
}
```

Keep in mind that on [TVM][tvm], maps are represented as [`Cell{:tact}`][cell] type, which is very gas-intensive. Also, nested maps will reach the [limits](#limits-and-drawbacks) faster than regular maps.

## Allowed types

Allowed key types:
Expand All @@ -28,7 +60,7 @@ Allowed value types:
* [`Bool{:tact}`](/book/types#booleans)
* [`Cell{:tact}`][cell]
* [`Address{:tact}`][p]
* [Struct](/book/structs-and-messages#structs)
* [Struct][struct]
* [Message](/book/structs-and-messages#messages)

## Serialization
Expand Down Expand Up @@ -486,7 +518,7 @@ It's often useful to set an upper-bound restriction on such maps, so that you [d

:::caution

Note, that manually keeping track of number of items or checking the length of such map is very error-prone and generally discouraged. Instead, try to wrap your map into the [Struct](/book/structs-and-messages#structs) and define [extension functions](/book/functions#extension-function) on it. See example in the Cookbook: [How to emulate an array using a map wrapped in a Struct](/cookbook/data-structures#array).
Note, that manually keeping track of number of items or checking the length of such map is very error-prone and generally discouraged. Instead, try to wrap your map into the [Struct][struct] and define [extension functions](/book/functions#extension-function) on it. See example in the Cookbook: [How to emulate an array using a map wrapped in a Struct](/cookbook/data-structures#array).

:::

Expand Down Expand Up @@ -543,6 +575,7 @@ If you still need a large map or an unbound (infinitely large) map, it's better
[p]: /book/types#primitive-types
[int]: /book/integers
[cell]: /book/cells#cells
[struct]: /book/structs-and-messages#structs

[hashmap]: https://docs.ton.org/develop/data-formats/tl-b-types#hashmap
[tvm]: https://docs.ton.org/learn/tvm-instructions/tvm-overview

0 comments on commit 596d2ce

Please sign in to comment.