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

feat: Maps page update #156

Merged
merged 11 commits into from
Apr 2, 2024
Merged

feat: Maps page update #156

merged 11 commits into from
Apr 2, 2024

Conversation

novusnota
Copy link
Member

@novusnota novusnota commented Mar 28, 2024

Added or refined:

  • .get()
  • .set()
  • .asCell()
  • Deletion of individual or all entries
  • Iteration over maps
  • Mention of issues with large maps and how to mitigate them:
    1. With upper-bounds
    2. Or with contract sharding

And everything with examples of Tact code, except for contract sharding, which will be added later as per tact-lang/tact#1151.

As a bonus, added two neat examples of using maps as arrays to Cookbook (with handy comments): one from @howardpen9 🔥, another from tact-by-example and @talkol 🔥

Closes #135
Closes #133

* All of the available stuff!
* And mention of issues with large maps and how to avoid them
@novusnota novusnota requested a review from anton-trunov March 28, 2024 14:22
pages/book/maps.mdx Outdated Show resolved Hide resolved
pages/book/maps.mdx Outdated Show resolved Hide resolved
pages/book/maps.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
novusnota and others added 2 commits March 28, 2024 20:28
Co-authored-by: Anton Trunov <anton.a.trunov@gmail.com>
@novusnota
Copy link
Member Author

Left to do:

image

And the same for arrPop() function just introduces.

@novusnota
Copy link
Member Author

novusnota commented Mar 31, 2024

@anton-trunov It seems like the gas usage with packing the map into structure with methods (with one persistent state variable array: Array, see below) is the same as in the previous example (with using two: arr and arrLength). Or this is the case for the Sandbox.

Code of the new example (works, tested :)
import "@stdlib/deploy";

struct Array {
    map: map<Int, Int>; // «array» of Int values as a map
    length: Int = 0;    // length of the «array», defaults to 0
}

extends mutates fun push(self: Array, item: Int) {
    self.map.set(self.length, item);
    self.length = self.length + 1;
}

extends mutates fun pop(self: Array): Int {
    require(self.length > 0, "No items in the array to delete!");

    // Note, that we use !! operator as we know for sure that the value would be there
    let lastItem: Int = self.map.get(self.length - 1)!!;
    self.map.set(self.length - 1, null); // delete the entry
    self.length = self.length - 1;       // decrease the length

    return lastItem;
}

extends fun getLast(self: Array): Int {
    require(self.length > 0, "No items in the array!");

    // Note, that we use !! operator as we know for sure that the value would be there
    return self.map.get(self.length - 1)!!;
}

contract MapsAsArrays with Deployable {
    // Persistent state variables
    array: Array; // structure defined above

    // Constructor (initialization) function of the contract
    init() {
        self.array = Array{map: emptyMap()}; // length defaults to 0
    }

    // Internal message receiver, which responds to a String message "push"
    receive("push") {
        // Add a new item and increase the counter
        self.array.push(42);
    }

    // Internal message receiver, which responds to a String message "pop"
    receive("pop") {
        // Remove the last item and decrease the counter
        self.array.pop();
    }

    // Internal message receiver, which responds to a String message "get_last"
    receive("get_last") {
        // Reply back with the latest item in the map if it exists, or raise an error
        self.reply(self.array.getLast().toCoinsString().asComment());
    }

    // Getter function for obtaining the «array»
    get fun map(): map<Int, Int> {
        return self.array.map;
    }

    // Getter function for obtaining the current length of the «array»
    get fun length(): Int {
        return self.array.length;
    }
}

Added that example to the Cookbook + added a note discussing potential issues of the current one.

@novusnota novusnota requested a review from anton-trunov March 31, 2024 21:50
Copy link
Member

@anton-trunov anton-trunov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like what you did for array emulation with maps packed in structs.
(btw, that example shows we need generic data structures in Tact)

pages/book/maps.mdx Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
pages/cookbook/index.mdx Outdated Show resolved Hide resolved
@novusnota
Copy link
Member Author

Ready for review. Added more examples and refined previous ones — Map emulating: Arrays, Stacks, CircularBuffers.

Copy link
Member

@anton-trunov anton-trunov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome

@anton-trunov anton-trunov merged commit e1216b6 into tact-lang:main Apr 2, 2024
1 check passed
@novusnota novusnota deleted the maps branch June 9, 2024 15:29
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The book should have a chapter on maps Mention in book/types#maps the storage issue with large maps
2 participants