diff --git a/.github/workflows/sync-motoko.yml b/.github/workflows/sync-motoko.yml new file mode 100644 index 00000000..204f84e8 --- /dev/null +++ b/.github/workflows/sync-motoko.yml @@ -0,0 +1,151 @@ +name: Motoko release check + +on: + schedule: + - cron: '0 8 * * 1' # Weekly on Monday + workflow_dispatch: + +jobs: + check: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + fetch-depth: 0 + + - name: Initialize motoko submodule + run: | + git config --global url."https://github.com/".insteadOf "git@github.com:" + git submodule update --init --depth 1 .sources/motoko + + - name: Get latest Motoko release tag + id: latest + run: | + LATEST=$(gh release view --repo caffeinelabs/motoko --json tagName -q .tagName) + # Normalize: ensure v prefix for consistency with VERSIONS file + [[ "$LATEST" == v* ]] || LATEST="v${LATEST}" + echo "tag=$LATEST" >> $GITHUB_OUTPUT + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get currently pinned version + id: current + run: | + CURRENT=$(grep '^motoko ' .sources/VERSIONS | awk '{print $2}') + echo "version=$CURRENT" >> $GITHUB_OUTPUT + + - name: Check if update needed + id: check + run: | + LATEST="${{ steps.latest.outputs.tag }}" + CURRENT="${{ steps.current.outputs.version }}" + BRANCH="infra/bump-motoko-${LATEST}" + + if [ "$LATEST" = "$CURRENT" ]; then + echo "Already at latest: $CURRENT" + echo "needed=false" >> $GITHUB_OUTPUT + elif git ls-remote --exit-code origin "refs/heads/${BRANCH}" > /dev/null 2>&1; then + echo "Branch $BRANCH already exists — PR likely open, skipping" + echo "needed=false" >> $GITHUB_OUTPUT + else + echo "New release: $LATEST (current: $CURRENT)" + echo "needed=true" >> $GITHUB_OUTPUT + fi + + - name: Bump submodule to new release + if: steps.check.outputs.needed == 'true' + run: | + TAG="${{ steps.latest.outputs.tag }}" + git -C .sources/motoko fetch --depth 1 origin "refs/tags/${TAG}:refs/tags/${TAG}" || \ + git -C .sources/motoko fetch --unshallow origin + git -C .sources/motoko checkout "$TAG" 2>/dev/null || \ + git -C .sources/motoko checkout "tags/${TAG}" + + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + if: steps.check.outputs.needed == 'true' + with: + node-version: 22 + cache: npm + + - name: Install dependencies + if: steps.check.outputs.needed == 'true' + run: npm ci + + - name: Initialize examples submodule (required for build) + if: steps.check.outputs.needed == 'true' + run: git submodule update --init --depth 1 .sources/examples + + - name: Run Motoko sync + if: steps.check.outputs.needed == 'true' + run: npm run sync:motoko + + - name: Build check + if: steps.check.outputs.needed == 'true' + run: npm run build + + - name: Update VERSIONS file + if: steps.check.outputs.needed == 'true' + run: | + NEW_TAG="${{ steps.latest.outputs.tag }}" + NEW_HASH=$(git -C .sources/motoko rev-parse --short HEAD) + sed -i "s|^motoko .*|motoko ${NEW_TAG} ${NEW_HASH}|" .sources/VERSIONS + + - name: Read sync warnings + if: steps.check.outputs.needed == 'true' + id: warnings + run: | + if [ -f /tmp/sync-motoko-warnings.txt ]; then + WARNINGS=$(cat /tmp/sync-motoko-warnings.txt) + echo "body<> $GITHUB_OUTPUT + echo "$WARNINGS" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + else + echo "body=" >> $GITHUB_OUTPUT + fi + + - name: Create PR + if: steps.check.outputs.needed == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + BRANCH="infra/bump-motoko-${{ steps.latest.outputs.tag }}" + git checkout -b "$BRANCH" + git add .sources/motoko .sources/VERSIONS docs/languages/motoko/ + git commit -m "chore: bump Motoko to ${{ steps.latest.outputs.tag }}" + git push -u origin "$BRANCH" + + WARNINGS="${{ steps.warnings.outputs.body }}" + { + echo "## Summary" + echo "" + echo "Automated bump of \`.sources/motoko\` from \`${{ steps.current.outputs.version }}\` to \`${{ steps.latest.outputs.tag }}\`." + echo "" + echo "- Ran \`npm run sync:motoko\` — synced docs from the new release" + echo "- Build passed ✓" + echo "" + if [ -n "$WARNINGS" ]; then + echo "## ⚠️ Warnings — manual review required" + echo "" + echo "$WARNINGS" + echo "" + fi + echo "## Checklist" + echo "" + echo "- [ ] Review synced content for breaking changes" + echo "- [ ] Check [release notes](https://github.com/caffeinelabs/motoko/releases/tag/${{ steps.latest.outputs.tag }}) for API or syntax changes that affect hand-written docs" + echo "- [ ] Verify any new sections or renamed files are handled correctly" + echo "" + echo "## Sync recommendation" + echo "" + echo "\`sync from caffeinelabs/motoko doc/md\`" + } > /tmp/pr-body.md + + gh pr create \ + --title "chore: bump Motoko to ${{ steps.latest.outputs.tag }}" \ + --body-file /tmp/pr-body.md + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/languages/motoko/base-core-migration.md b/docs/languages/motoko/base-core-migration.md new file mode 100644 index 00000000..6185e780 --- /dev/null +++ b/docs/languages/motoko/base-core-migration.md @@ -0,0 +1,970 @@ +--- +sidebar_position: 12 +description: "Motoko language documentation" +title: "Motoko `base` to `core` migration guide" +--- + +* [GitHub repository](https://github.com/dfinity/motoko-core) +* [Documentation](https://mops.one/core) + +The `core` package is a new and improved standard library for Motoko, focusing on: +* AI-friendly design patterns. +* Familiarity coming from languages such as JavaScript, Python, Java, and Rust. +* Simplified usage of data structures in stable memory. +* Consistent naming conventions and parameter ordering. + +This page provides a comprehensive guide for migrating from the `base` Motoko package to the new `core` package. + +### Project configuration + +Add the following to your `mops.toml` file to begin using the `core` package: + +```toml +[dependencies] +core = "0.0.0" # Check the latest version: https://mops.one/core +``` + +If you are migrating an existing project, you can keep the `base` import and gradually transition to using the new API. + +### Important considerations + +:::warning[Version requirements] +The `core` package depends on new language features, so make sure to update to the latest dfx (0.28+) or Motoko compiler (0.15+) before migrating. +::: + +When updating to the `core` package: + +- All data structures can now be stored in stable memory without the need for pre-upgrade/post-upgrade hooks, provided those data structures are instantiated at stable type arguments. +- `range()` functions in the `core` library are now exclusive rather than inclusive! Keep this in mind when replacing `Iter.range()` with `Nat.range()`. +- Functions previously named `vals()` are renamed to `values()`. This also applies to fields. For example, `array.vals()` can be replaced with `array.values()`. +- Hash-based data structures are no longer included in the standard library. It is encouraged to use ordered maps and sets for improved security. +- In some cases, it won't be possible to fully migrate to `core` due to removal of some features in `base`. In these cases, you can continue using both packages side-by-side or search for [Mops packages](https://mops.one/) built by the community. + +For details on function signatures, please refer to the official [documentation](https://mops.one/core). + +Also, feel free to ask for help by posting on the [ICP developer forum](https://forum.dfinity.org/c/developers) or opening a GitHub issue on the [`dfinity/motoko-core`](https://github.com/dfinity/motoko-core/issues) repository. + +## Module changes + +### 1. New modules + +The following modules are **new** in the `core` package: + +- `List` - Mutable list +- `Map` - Mutable map +- `Queue` - Mutable double-ended queue +- `Set` - Mutable set +- `Runtime` - Runtime utilities and assertions +- `Tuples` - Tuple utilities +- `Types` - Common type definitions +- `VarArray` - Mutable array operations +- `pure/List` - Immutable list (originally `mo:base/List`) +- `pure/Map` - Immutable map (originally `mo:base/OrderedMap`) +- `pure/RealTimeQueue` - Queue implementation with performance tradeoffs +- `pure/Set` - Immutable set (originally `mo:base/OrderedSet`) + +### 2. Renamed modules + +| Base package | Core package | Notes | +| ------------------------------ | ------------------ | --------------------------------------------------- | +| `ExperimentalCycles` | `Cycles` | Stabilized module for cycle management | +| `ExperimentalInternetComputer` | `InternetComputer` | Stabilized low-level ICP interface | +| `Deque` | `pure/Queue` | Enhanced double-ended queue becomes immutable queue | +| `List` | `pure/List` | Original immutable list moved to `pure/` namespace | +| `OrderedMap` | `pure/Map` | Ordered map moved to `pure/` namespace | +| `OrderedSet` | `pure/Set` | Ordered set moved to `pure/` namespace | + +:::note +The `pure/` namespace contains immutable (purely functional) data structures where operations return new values rather than modifying in place. The namespace makes it clear which data structures are mutable and which are immutable. +::: + +### 3. Removed modules + +The following modules have been **removed** in the core package: + +- `AssocList` - Use `Map` or `pure/Map` instead +- `Buffer` - Use `List` or `VarArray` instead +- `ExperimentalStableMemory` - Deprecated +- `Hash` - Vulnerable to hash collision attacks +- `HashMap` - Use `Map` or `pure/Map` +- `Heap` - Use `Map` or `Set` instead +- `IterType` - Merged into `Types` module +- `None` - Use `switch x {}` in place of `None.impossible(x)` +- `Prelude` - Merged into `Debug` and `Runtime` +- `RBTree` - Use `Map` instead +- `Trie` - Use `Map` instead +- `TrieMap` - Use `Map` or `pure/Map` instead +- `TrieSet` - Use `Set` or `pure/Set` instead + +:::note +Modules like `Random`, `Region`, `Time`, `Timer`, and `Stack` still exist in core but with modified APIs. +::: + +## Data structure improvements + +The `core` package brings significant changes to data structures, making a clear separation between mutable and immutable (purely functional) APIs. All data structures can now be stored directly in stable memory. + +| Data Structure | Description | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **List** | Mutable list (originally [`mo:vector`](https://mops.one/vector)) | +| **Map** | Mutable map (originally [`mo:stableheapbtreemap`](https://mops.one/stableheapbtreemap)) | +| **Queue** | Mutable queue +| **Set** | Mutable set | +| **Array** | Immutable array | +| **VarArray** | Mutable array | +| **pure/List** | Immutable list (originally `mo:base/List`) | +| **pure/Map** | Immutable map (originally `mo:base/OrderedMap`) | +| **pure/Set** | Immutable set (originally `mo:base/OrderedSet`) | +| **pure/Queue** | Immutable queue (orginally `mo:base/Deque`) | +| **pure/RealTimeQueue** | Immutable queue with [constant-time operations](https://drops.dagstuhl.de/storage/00lipics/lipics-vol268-itp2023/LIPIcs.ITP.2023.29/LIPIcs.ITP.2023.29.pdf) | + +## Interface changes by module + +### [`Array`](https://mops.one/core/docs/Array) + +#### Renamed functions +- `append()` → `concat()` +- `chain()` → `flatMap()` +- `freeze()` → `fromVarArray()` +- `init()` → `repeat()` with reversed argument order +- `make()` → `singleton()` +- `mapFilter()` → `filterMap()` +- `slice()` → `range()` +- `subArray()` → `sliceToArray()` +- `thaw()` → `toVarArray()` +- `vals()` → `values()` + +#### New functions +- `all()` - Check if all elements satisfy predicate +- `any()` - Check if any element satisfies predicate +- `compare()` - Compare two arrays +- `empty()` - Create empty array +- `enumerate()` - Get indexed iterator +- `findIndex()` - Find index of first matching element +- `forEach()` - Apply function to each element +- `fromIter()` - Create array from iterator +- `isEmpty()` - Check if array is empty +- `join()` - Join arrays from iterator +- `toText()` - Convert array to text representation + +#### Parameter order changes +- `indexOf(element, array, equal)` → `indexOf(array, equal, element)` +- `lastIndexOf(element, array, equal)` → `lastIndexOf(array, equal, element)` +- `nextIndexOf(element, array, fromInclusive, equal)` → `nextIndexOf(array, equal, element, fromInclusive)` +- `prevIndexOf(element, array, fromExclusive, equal)` → `prevIndexOf(array, equal, element, fromExclusive)` + +#### Removed functions +- `take()` - Use `sliceToArray()` instead +- `sortInPlace()` - Use `VarArray.sortInPlace()` instead +- `tabulateVar()` - Use `VarArray.tabulate()` instead + +### [`Blob`](https://mops.one/core/docs/Blob) + +#### Modified functions +- `fromArrayMut()` → `fromVarArray()` +- `hash()` - Return type changed from `Nat32` to `Types.Hash` +- `toArrayMut()` → `toVarArray()` + +#### New functions +- `empty()` - Create an empty blob (`"" : Blob`) +- `isEmpty()` - Check if blob is empty +- `size()` - Get number of bytes in a blob (equivalent to `blob.size()`) + +### [`Bool`](https://mops.one/core/docs/Bool) + +#### Renamed functions +- `logand()` → `logicalAnd()` +- `lognot()` → `logicalNot()` +- `logor()` → `logicalOr()` +- `logxor()` → `logicalXor()` + +#### New functions +- `allValues()` - Iterator over all boolean values + +### [`Char`](https://mops.one/core/docs/Char) + +#### Renamed functions +- `isLowercase()` → `isLower()` +- `isUppercase()` → `isUpper()` + +### [`Debug`](https://mops.one/core/docs/Debug) + +#### Added functions +- `todo()` - Replaces `Prelude.nyi()` + +#### Removed functions +- `trap()` - Moved to `Runtime.trap()` + +### [`Float`](https://mops.one/core/docs/Float) + +#### Modified functions +- `equal()` - Now requires epsilon parameter +- `notEqual()` - Now requires epsilon parameter + +#### Removed functions +- `equalWithin()`, `notEqualWithin()` - Use `equal()` and `notEqual()` with epsilon + +### [`Iter`](https://mops.one/core/docs/Iter) + +`Iter.range()` has been removed in favor of type-specific range functions such as `Nat.range()`, `Int.range()`, `Nat32.range()`, etc. These functions have an **exclusive upper bound**, in contrast to the original inclusive upper bound of `Iter.range()`. + +```motoko no-repl +import Int "mo:base/Int"; +import Debug "mo:base/Debug"; + +persistent actor { + // Iterate through -3, -2, -1, 0, 1, 2 (exclusive upper bound) + for (number in Int.range(-3, 3)) { + Debug.print(debug_show number); + }; + + // Iterate through -3, -2, -1, 0, 1, 2, 3 + for (number in Int.rangeInclusive(-3, 3)) { + Debug.print(debug_show number); + }; +} +``` + +`rangeInclusive()` is included for use cases with an inclusive upper bound. The original `Iter.range()` corresponds to `Nat.rangeInclusive()`. + +Helper functions have been added, such as `allValues()`, for each finite type in the `base` package. + +### [`Int`](https://mops.one/core/docs/Int) + +#### New functions +- `fromNat()` - Convert Nat to Int +- `fromText()` - Parse Int from text +- `range()` - Create iterator over range +- `rangeBy()` - Create iterator with step +- `rangeByInclusive()` - Inclusive range with step +- `rangeInclusive()` - Inclusive range +- `toNat()` - Convert Int to Nat (safe conversion) + +#### Modified functions +- `fromText()` - Now returns `null` instead of `?0` for the inputs "+" and "-" + +#### Removed functions +- `hash()` +- `hashAcc()` + +### [`Nat`](https://mops.one/core/docs/Nat) + +#### New functions +- `allValues()` - Iterator over all natural numbers +- `bitshiftLeft()` / `bitshiftRight()` - Bit shifting operations +- `fromInt()` - Safe conversion from Int +- `fromText()` - Parse Nat from text +- `range()`, `rangeInclusive()` - Range iterators +- `rangeBy()`, `rangeByInclusive()` - Range with step +- `toInt()` - Convert to Int + +### [`Int8`, `Int16`, `Int32`, `Int64`, `Nat8`, `Nat16`, `Nat32`, `Nat64`](https://mops.one/core) + +#### Renamed fields + +- `maximumValue` → `maxValue` +- `minimumValue` → `minValue` + +#### New functions +- `allValues()` - Iterator over all values in range +- `range()`, `rangeInclusive()` - Range iterators (replaces `Iter.range()`) +- `explode()` - Slice into constituent bytes (only for sizes `16`, `32`, `64`) + +### [`Option`](https://mops.one/core/docs/Option) + +#### Renamed functions +- `make()` → `some()` - Create option from value +- `iterate()` → `forEach()` - Apply function to option value + +#### New functions +- `compare()` - Compare two options +- `toText()` - Convert option to text representation + +#### Removed functions +- `assertNull()` - Removed in favor of pattern matching +- `assertSome()` - Removed in favor of pattern matching + +### [`Order`](https://mops.one/core/docs/Order) + +#### New functions +- `allValues()` - Iterator over all order values (`#less`, `#equal`, `#greater`) + +### [`Random`](https://mops.one/core/docs/Random) + +The `Random` module has been completely redesigned in the core package with a new API that provides better control over random number generation and supports both pseudo-random and cryptographic random number generation. + +```motoko +import Random "mo:core/Random"; + +persistent actor { + transient let random = Random.crypto(); + + public func main() : async () { + let coin = await* random.bool(); // true or false + let byte = await* random.nat8(); // 0 to 255 + let number = await* random.nat64(); // 0 to 2^64 + let numberInRange = await* random.natRange(0, 10); // 0 to 9 + } +} +``` + +#### New classes +- `Random` - Synchronous pseudo-random number generator for simulations and testing +- `AsyncRandom` - Asynchronous cryptographic random number generator using ICP entropy + +#### Class methods +- `bool()` - Random choice between `true` and `false` +- `nat8()` - Random `Nat8` value in range `[0, 256)` +- `nat64()` - Random `Nat64` value in range `[0, 2^64)` +- `nat64Range(from, to)` - Random `Nat64` in range `[from, to)` +- `natRange(from, to)` - Random `Nat` in range `[from, to)` +- `intRange(from, to)` - Random `Int` in range `[from, to)` + +#### New functions +- `emptyState()` - Initialize empty random number generator state +- `seedState()` - Initialize pseudo-random state with 64-bit seed +- `seed()` - Create pseudo-random generator from seed +- `seedFromState()` - Create pseudo-random generator from state +- `crypto()` - Create cryptographic random generator using ICP entropy +- `cryptoFromState()` - Create cryptographic generator from state + +### [`Result`](https://mops.one/core/docs/Result) + +#### New functions +- `all()` - Check all results in iterator +- `any()` - Check any result satisfies predicate +- `forOk()` - Apply function to `#ok` value +- `forErr()` - Apply function to `#err` value +- `fromBool()` - Create Result from boolean + +### [`Text`](https://mops.one/core/docs/Text) + +#### Renamed functions +- `toLowercase()` → `toLower()` +- `toUppercase()` → `toUpper()` +- `translate()` → `flatMap()` + +#### New functions +- `isEmpty()` - Check if text is empty +- `reverse()` - Swap the order of characters +- `toText()` - Identity function + +#### Removed functions +- `hash()` +- `fromList()` - Use `fromIter()` with list iterator instead +- `toList()` - Use `toIter()` and convert to list if needed + +## Data structure migration examples + +This section provides detailed migration examples showing how to convert common data structures from the `base` package to the `core` package. Each example demonstrates: + +1. **Original implementation** using the `base` package with pre/post-upgrade hooks +2. **Updated implementation** using the `core` package with automatic stable memory support +3. **Migration pattern** using the new `with migration` syntax for seamless data structure conversion + +:::tip +The new migration pattern allows you to automatically convert existing stable data from `base` package structures to `core` package structures during canister upgrades. The migration function runs once during the first upgrade and the converted data becomes the new stable state. +::: + +### Understanding the migration pattern + +The `with migration` syntax follows this structure: + +```motoko +( + with migration = func( + state : { + // Original state types + } + ) : { + // New state types + } = { + // Conversion logic + } +) +persistent actorApp { + // New stable declarations +}; +``` + +It's also possible to use a function defined in an imported module: + +```motoko +import { migrate } "Migration"; + +(with migration = migrate) +persistent actorApp { + // New stable declarations +}; +``` + +This pattern ensures that existing stable data is preserved and converted to the new format during canister upgrades. + +### `Buffer` + +#### Original (`base`) + +```motoko +import Buffer "mo:base/Buffer"; + +persistent actor{ + type Item = Text; + + stable var items : [Item] = []; + let buffer = Buffer.fromArray(items); + + system func preupgrade() { + items := Buffer.toArray(buffer); + }; + + system func postupgrade() { + items := []; + }; + + public func add(item : Item) : async () { + buffer.add(item); + }; + + public query func getItems() : async [Item] { + Buffer.toArray(buffer); + }; +}; +``` + +#### Updated (`core`) + +```motoko +import List "mo:core/List"; + +( + with migration = func( + state : { + var items : [App.Item]; + } + ) : { + list : List.List; + } = { + list = List.fromArray(state.items); + } +) +persistent actorApp { + public type Item = Text; // `public` for migration + + stable let list = List.empty(); + + public func add(item : Item) : async () { + List.add(list, item); + }; + + public query func getItems() : async [Item] { + List.toArray(list); + }; +}; +``` + +### `Deque` + +#### Original (`base`) + +```motoko +import Deque "mo:base/Deque"; + +persistent actor{ + type Item = Text; + + stable var deque = Deque.empty(); + + public func put(item : Item) : async () { + deque := Deque.pushBack(deque, item); + }; + + public func take() : async ?Item { + switch (Deque.popFront(deque)) { + case (?(item, newDeque)) { + deque := newDeque; + ?item; + }; + case null { null }; + }; + }; +}; +``` + +#### Updated (`core`) + +```motoko +import Deque "mo:base/Deque"; // For migration +import Queue "mo:core/Queue"; + +( + with migration = func( + state : { + var deque : Deque.Deque; + } + ) : { + queue : Queue.Queue; + } { + let queue = Queue.empty(); + label l loop { + switch (Deque.popFront(state.deque)) { + case (?(item, deque)) { + Queue.pushBack(queue, item); + state.deque := deque; + }; + case null { + break l; + }; + }; + }; + { queue }; + } +) actor App { + public type Item = Text; // `public` for migration + + stable let queue = Queue.empty(); + + public func put(item : Item) : async () { + Queue.pushBack(queue, item); + }; + + public func take() : async ?Item { + Queue.popFront(queue); + }; +}; +``` + +### `HashMap` + +#### Original (`base`) + +```motoko +import HashMap "mo:base/HashMap"; +import Text "mo:base/Text"; +import Iter "mo:base/Iter"; + +persistent actor{ + stable var mapEntries : [(Text, Nat)] = []; + let map = HashMap.fromIter(mapEntries.vals(), 10, Text.equal, Text.hash); + + system func preupgrade() { + mapEntries := Iter.toArray(map.entries()); + }; + + system func postupgrade() { + mapEntries := []; + }; + + public func update(key : Text, value : Nat) : async () { + map.put(key, value); + }; + + public func remove(key : Text) : async ?Nat { + map.remove(key); + }; + + public query func getItems() : async [(Text, Nat)] { + Iter.toArray(map.entries()); + }; +}; +``` + +#### Updated (`core`) + +```motoko +import Map "mo:core/Map"; +import Text "mo:core/Text"; +import Iter "mo:core/Iter"; + +( + with migration = func( + state : { + var mapEntries : [(Text, Nat)]; + } + ) : { + map : Map.Map; + } = { + map = Map.fromIter(state.mapEntries.vals(), Text.compare); + } +) +persistent actor{ + stable let map = Map.empty(); + + public func update(key : Text, value : Nat) : async () { + Map.add(map, Text.compare, key, value); + }; + + public func remove(key : Text) : async ?Nat { + Map.take(map, Text.compare, key); + }; + + public query func getItems() : async [(Text, Nat)] { + Iter.toArray(Map.entries(map)); + }; +}; +``` + +### `OrderedMap` + +#### Original (`base`) + +```motoko +import OrderedMap "mo:base/OrderedMap"; +import Text "mo:base/Text"; +import Iter "mo:base/Iter"; + +persistent actor{ + let textMap = OrderedMap.Make(Text.compare); + stable var map = textMap.empty(); + + public func update(key : Text, value : Nat) : async () { + map := textMap.put(map, key, value); + }; + + public func remove(key : Text) : async ?Nat { + let (newMap, removedValue) = textMap.remove(map, key); + map := newMap; + removedValue; + }; + + public query func getItems() : async [(Text, Nat)] { + Iter.toArray(textMap.entries(map)); + }; +}; +``` + +#### Updated (`core`) + +```motoko +import OrderedMap "mo:base/OrderedMap"; // For migration +import Map "mo:core/Map"; +import Text "mo:core/Text"; +import Iter "mo:core/Iter"; + +( + with migration = func( + state : { + var map : OrderedMap.Map; + } + ) : { + map : Map.Map; + } { + let compare = Text.compare; + let textMap = OrderedMap.Make(compare); + let map = Map.fromIter(textMap.entries(state.map), compare); + { map }; + } +) +persistent actor{ + stable let map = Map.empty(); + + public func update(key : Text, value : Nat) : async () { + Map.add(map, Text.compare, key, value); + }; + + public func remove(key : Text) : async ?Nat { + Map.take(map, Text.compare, key); + }; + + public query func getItems() : async [(Text, Nat)] { + Iter.toArray(Map.entries(map)); + }; +}; +``` + +### `OrderedSet` + +#### Original (`base`) + +```motoko +import OrderedSet "mo:base/OrderedSet"; +import Text "mo:base/Text"; +import Iter "mo:base/Iter"; + +persistent actor{ + type Item = Text; + + let textSet = OrderedSet.Make(Text.compare); + stable var set = textSet.empty(); + + public func add(item : Item) : async () { + set := textSet.put(set, item); + }; + + public func remove(item : Item) : async Bool { + let oldSize = textSet.size(set); + set := textSet.delete(set, item); + oldSize > textSet.size(set); + }; + + public query func getItems() : async [Item] { + Iter.toArray(textSet.vals(set)); + }; +}; +``` + +#### Updated (`core`) + +```motoko +import OrderedSet "mo:base/OrderedSet"; // For migration +import Set "mo:core/Set"; +import Text "mo:core/Text"; +import Iter "mo:core/Iter"; + +( + with migration = func( + state : { + var set : OrderedSet.Set; + } + ) : { + set : Set.Set; + } { + let compare = Text.compare; + let textSet = OrderedSet.Make(compare); + let set = Set.fromIter(textSet.vals(state.set), compare); + { set }; + } +) +persistent actorApp { + public type Item = Text; // `public` for migration + + stable let set = Set.empty(); + + public func add(item : Item) : async () { + Set.add(set, Text.compare, item); + }; + + public func remove(item : Item) : async Bool { + Set.delete(set, Text.compare, item); + }; + + public query func getItems() : async [Item] { + Iter.toArray(Set.values(set)); + }; +}; +``` + +### `Trie` + +#### Original (`base`) + +```motoko +import Trie "mo:base/Trie"; +import Text "mo:base/Text"; +import Iter "mo:base/Iter"; + +persistent actor{ + type Key = Text; + type Value = Nat; + + stable var trie : Trie.Trie = Trie.empty(); + + public func update(key : Key, value : Value) : async () { + let keyHash = Text.hash(key); + trie := Trie.put(trie, { key = key; hash = keyHash }, Text.equal, value).0; + }; + + public func remove(key : Key) : async ?Value { + let keyHash = Text.hash(key); + let (newTrie, value) = Trie.remove(trie, { key = key; hash = keyHash }, Text.equal); + trie := newTrie; + value; + }; + + public query func getItems() : async [(Key, Value)] { + Iter.toArray(Trie.iter(trie)); + }; +}; +``` + +#### Updated (`core`) + +```motoko +import Trie "mo:base/Trie"; // For migration +import Map "mo:core/Map"; +import Text "mo:core/Text"; +import Iter "mo:core/Iter"; + +( + with migration = func( + state : { + var trie : Trie.Trie; + } + ) : { + map : Map.Map; + } = { + map = Map.fromIter(Trie.iter(state.trie), Text.compare); + } +) +persistent actor{ + stable let map = Map.empty(); + + public func update(key : Text, value : Nat) : async () { + Map.add(map, Text.compare, key, value); + }; + + public func remove(key : Text) : async ?Nat { + Map.take(map, Text.compare, key); + }; + + public query func getItems() : async [(Text, Nat)] { + Iter.toArray(Map.entries(map)); + }; +}; +``` + +### `TrieMap` + +#### Original (`base`) + +```motoko +import TrieMap "mo:base/TrieMap"; +import Text "mo:base/Text"; +import Iter "mo:base/Iter"; + +persistent actor{ + stable var mapEntries : [(Text, Nat)] = []; + let map = TrieMap.fromEntries(mapEntries.vals(), Text.equal, Text.hash); + + system func preupgrade() { + mapEntries := Iter.toArray(map.entries()); + }; + + system func postupgrade() { + mapEntries := []; + }; + + public func update(key : Text, value : Nat) : async () { + map.put(key, value); + }; + + public func remove(key : Text) : async ?Nat { + map.remove(key); + }; + + public query func getItems() : async [(Text, Nat)] { + Iter.toArray(map.entries()); + }; +}; +``` + +#### Updated (`core`) + +```motoko +import Map "mo:core/Map"; +import Text "mo:core/Text"; +import Iter "mo:core/Iter"; + +( + with migration = func( + state : { + var mapEntries : [(Text, Nat)]; + } + ) : { + map : Map.Map; + } = { + map = Map.fromIter(state.mapEntries.values(), Text.compare); + } +) +persistent actor{ + stable let map = Map.empty(); + + public func update(key : Text, value : Nat) : async () { + Map.add(map, Text.compare, key, value); + }; + + public func remove(key : Text) : async ?Nat { + Map.take(map, Text.compare, key); + }; + + public query func getItems() : async [(Text, Nat)] { + Iter.toArray(Map.entries(map)); + }; +}; +``` + +### `TrieSet` + +#### Original (`base`) + +```motoko +import TrieSet "mo:base/TrieSet"; +import Text "mo:base/Text"; + +persistent actor{ + type Item = Text; + + stable var set : TrieSet.Set = TrieSet.empty(); + + public func add(item : Item) : async () { + set := TrieSet.put(set, item, Text.hash(item), Text.equal); + }; + + public func remove(item : Item) : async Bool { + let contained = TrieSet.mem(set, item, Text.hash(item), Text.equal); + set := TrieSet.delete(set, item, Text.hash(item), Text.equal); + contained; + }; + + public query func getItems() : async [Item] { + TrieSet.toArray(set); + }; +}; +``` + +#### Updated (`core`) + +```motoko +import Set "mo:core/Set"; +import Text "mo:core/Text"; +import Iter "mo:core/Iter"; +import TrieSet "mo:base/TrieSet"; + +( + with migration = func( + state : { + var set : TrieSet.Set; + } + ) : { + set : Set.Set; + } = { + set = Set.fromIter(TrieSet.toArray(state.set).vals(), Text.compare); + } +) +persistent actorApp { + public type Item = Text; // `public` for migration + + stable let set = Set.empty(); + + public func add(item : Item) : async () { + Set.add(set, Text.compare, item); + }; + + public func remove(item : Item) : async Bool { + Set.delete(set, Text.compare, item); + }; + + public query func getItems() : async [Item] { + Iter.toArray(Set.values(set)); + }; +}; +``` + +## Troubleshooting + +### Version compatibility errors + +If you encounter errors like `field Array_tabulateVar does not exist in module`, this indicates a version mismatch between your Motoko compiler and the `core` package. + +**Solution:** +2. Ensure you're using the latest Motoko compiler version +3. Update the `core` package to the latest version in your `mops.toml` +4. Clean and rebuild your project: `dfx stop && dfx start --clean` + +### Migration issues + +If you experience issues with the migration pattern: +1. Ensure your project structure follows the new `with migration` syntax exactly +2. Verify that all types referenced in the migration function are accessible (marked as `public` if needed) +3. Test the migration incrementally by converting one data structure at a time + +For additional help, visit the ICP [developer forum](https://forum.dfinity.org/c/developers) or [Discord community](https://discord.internetcomputer.org). diff --git a/docs/languages/motoko/fundamentals/actors-async.md b/docs/languages/motoko/fundamentals/actors-async.md new file mode 100644 index 00000000..7576abdb --- /dev/null +++ b/docs/languages/motoko/fundamentals/actors-async.md @@ -0,0 +1,394 @@ +--- +sidebar_position: 1 +description: "Motoko language documentation" +title: "Actors & async data" +--- + +The actor programming model was designed to solve concurrency issues by encapsulating [state](/languages/motoko/fundamentals/state) and computation within independent units called **actors**. + +The actor model is built on four key principles: + +* **Isolation**: Actors are isolated and communicate solely through message passing. +* **Concurrency**: Actors can receive and process messages concurrently. +* **Fault tolerance**: Actors operate independently and can fail without affecting others. +* **Location transparency**: Actors can reside on any machine within a distributed system. + +In Motoko, actors have dedicated syntax and type rules that support asynchronous, message-based communication: + +* **Shared functions** handle messaging between actors. These functions return **futures** (values of type `async T`) and are accessible to remote callers. Shared functions come with restrictions. Both their arguments and return values must be **shared types**, a subset of types that includes immutable data, actor references, and shared function references, but excludes local function references and mutable data (like `var` or mutable arrays). + +* A **future**, `f`, has the type `async T` and represents a value of type `T` that will be available later. + +* To retrieve the result of a future, use `await f`, which pauses execution until the future is resolved and returns a value of type `T`. `await? f` can be used when the the future is likely resolved and the state commit semantics is irrelevant. + +* These restrictions help prevent shared mutable state from being introduced via messaging. Only immutable, shared data can be sent between actors through shared functions. + +* All mutable state should be encapsulated within the actor or actor class. A Motoko source file defining an actor typically starts with `import` statements, followed by the `actor` or `actor class` declaration. + +## `async` / `await` + +Motoko, like many other languages, offers `async` and `await` to support convenient programming with asynchronous functions and computations. + +When you run an asynchronous expression, like calling a shared function or creating a local `async` block, it returns a **future**, which is a placeholder for a result that will be available later. + +Instead of making the caller wait, the message is sent and queued, and the future is immediately returned. The caller can continue doing other work and later use `await` to pause until the future is ready and get the result. + +You can also attach extra information to an async call using a prefixed parenthetical in the form `(base with attr₁ = v₁; attr₂ = v₂; …)` where `base` is an optional record containing (e.g., default) attributes. Accepted attributes are currently `cycles : Nat`, specifying the amount of cycles to be sent along with the message, and `timeout : Nat32` to modify the deadline and restrict the time span while the receiver can reply. + +The combination of `async`/`await` constructs simplifies asynchronous programming by allowing `await`s to be embedded within ordinary sequential code, without requiring tricky management of asynchronous callbacks. + +## Traps and commit points + +A trap is a non-recoverable runtime failure in Motoko, caused by errors such as: + +* Division by zero. +* Out-of-bounds array access. +* Numeric overflow. +* Exceeding cycle limits. +* Failing an assertion. +* An explicit call to `Debug.trap()`. + +When a shared function executes without evaluating an `await` expression, it never suspend and thus runs atomically, meaning its execution cannot be interleaved with that of another message. Functions that don't contain any `await` expressions are syntactically atomic and guarantee interference-free execution from start to finish. + +### Commit points + +If an atomic shared function traps during execution, it has no visible effect. Any state changes are reverted, and messages sent are revoked. This is because all changes are tentative during execution and only become permanent once a commit point is reached. + +The commit points, where tentative state changes and message sends are irrevocably committed, are: + +* Implicit exit from a shared function by producing a result. + +* Explicit exit via `return` or `throw` expressions. + +* Execution of an `await` expression, which suspends the function and commits all changes up to that point. + +### Traps + +A trap will only revoke changes made since the last commit point. In particular, in a non-atomic function that does multiple awaits, a trap will only revoke changes attempted since the last await. All preceding effects will have been committed and cannot be undone. + +Consider the following stateful `Atomicity` actor: + +``` motoko no-repl file=../../examples/atomicity.mo +``` + +Calling the shared function `atomic()` results in an error because it traps before completing. Since the trap happens before any `await` or return, all changes are discarded. The variable `s` stays at 0, and `pinged` remains false. Even though `atomic()` calls `ping()`, that message is only queued and never sent because no commit point is reached. + +Calling `nonAtomic()` also fails with an error, but the state is partially updated. In this case, `s` ends up as 3, and `pinged` is true. This happens because the first `await` commits all prior changes, including the message send. The second `await` causes another commit and suspends execution, allowing other messages to be processed before the trap occurs. + + +## Async functions + +Here is an example program that uses async functions: + +```motoko +persistent actor Counter { + + var count = 0; + + public shared func inc() : async () { count += 1 }; + + public shared func read() : async Nat { count }; + + public shared func bump() : async Nat { + count += 1; + count; + }; +}; +``` + +The `Counter` actor declares one field and three public, shared functions: + +- The field `count` is mutable, initialized to zero and implicitly `private`. + +- Function `inc()` asynchronously increments the counter and returns a future of type `async ()` for synchronization. + +- Function `read()` asynchronously reads the counter value and returns a future of type `async Nat` containing its value. + +- Function `bump()` asynchronously increments and reads the counter. + +The only way to read or modify the state (`count`) of the `Counter` actor is through its shared functions. + +## Using `await` to consume `async` futures + +The caller of a shared function typically receives a future, a value of type `async T` for some `T`. + +The only thing the caller can do with this future is wait for it to be completed by the producer, throw it away, or store it for later use. + +To access the result of an `async` value, the receiver of the future uses an `await` expression. + +For example, to use the result of `Counter.read()` above, we can first bind the future to an identifier `a`, and then `await a` to retrieve the underlying [`Nat`](https://mops.one/core/docs/Nat), `n`: + +``` motoko no-repl +let a : async Nat = Counter.read(); +let n : Nat = await a; +``` + +The first line immediately receives a future of the counter value, but does not wait for it, and thus cannot use it as a natural number yet. + +The second line `await`s this future and extracts the result, a natural number. This line may suspend execution until the future has been completed. + +Typically, one rolls the two steps into one and just awaits an asynchronous call directly: + +``` motoko no-repl +let n : Nat = await Counter.read(); +``` + +Unlike a local function call, which waits for the result before continuing, a shared function call returns a future immediately without blocking. Later, calling `await` on that future pauses the current task until the future is finished. When the future completes, `await` either returns the result or throws an error if the future ended with one. + +If you `await` the same future again, it just returns the same result or error. Even if the future is already done, `await` will briefly suspend all pending state changes and outgoing messages. This means that you can rely on every `await` to commit state, whether its future is still in progress or already completed. + +## Using `await?` to efficiently await concurrent futures + +An `await` will always suspend execution and commit state, even if its future is already complete. + +When several futures are issued in parallel and racing to complete, it can be more efficient to opt out of the unconditional behavior of `await` and immediately continue with a result when it is available: + +``` motoko no-repl +let a : async Nat = CounterA.read(); +let b : async Nat = CounterB.read(); +let sum : Nat = (await a) + (await? b); +``` + +Here the futures `a` and `b` are racing to complete, and it is likely that the first `await` on `a` will resume with `b` already completed. +Using `await? b` ensures that `b`'s result can be used immediately, if available, without an unnecessary suspension. + +:::danger + +Since a commit of global state may not happen when using `await?`, this construct should be only used when the commit can be safely omitted. + +::: + + +## Using parentheticals to modify message send modalities + +In the examples above, messages sent to the `Counter` actor do not include cycles and will never timeout when waiting for their results. However, you can change these behaviors by adding a parenthetical expression that modifies the message’s attributes. + +To send cycles with a message, you can write: + +```motoko no-repl +let a = (with cycles = 42_000_000) Counter.bump(); +``` + +To set a timeout for awaiting the message result, which is useful when you want a best-effort response rather than a guaranteed one, you can write: + +```motoko no-repl +let a = (with timeout = 25) Counter.bump(); +``` + +You can also define a custom default set of attributes as a record and then extend it with additional attributes in the parenthetical: + +```motoko no-repl +let boundedWait = { timeout = 25 }; +let a = (boundedWait with cycles = 42_000_000) Counter.bump(); +``` + +This approach lets you easily customize message sending with cycles and timeouts. + +:::danger + +A function that does not use `await` runs atomically, meaning nothing else can change the actor’s state while it’s running. But if the function uses `await`, it can be paused, and during that pause, other messages may change the actor’s state. It’s up to the programmer to handle these possible changes safely. However, any state changes made before the `await` are guaranteed to be saved. + +For example, the implementation of `bump()` above is guaranteed to increment and read the value of `count`, in one atomic step. The following alternative implementation does not have the same semantics and allows another client of the actor to interfere with its operation. + +``` motoko no-repl + public shared func bump() : async Nat { + await inc(); + await read(); + }; +``` + +Each `await` suspends execution, allowing an interloper to change the state of the actor. By design, the explicit `await`s make the potential points of interference clear to the reader. + +::: + +## Async actors + +In Motoko, each communicating component is an actor, encapsulating its own state and behavior. Here's a simple three-line example that demonstrates basic actor usage: + +```motoko no-repl +let result1 = service1.computeAnswer(params); +let result2 = service2.computeAnswer(params); +finalStep(await result1, await result2) +``` + +This program’s behavior can be summarized as: + +1. The program makes two requests (lines 1 and 2) to two distinct services, each implemented as a Motoko actor or canister smart contract implemented in some other language. + +2. The program waits for each result to be ready (line 3) using the keyword `await` on each result value. + +3. The program uses both results in the final step (line 3) by calling the `finalStep` function. + +Services **interleave** their execution to reduce latency instead of waiting for each other. Without language support, this kind of interleaving quickly becomes complex and hard to manage. + +Even with just a single async call, Motoko’s abstractions help keep the code clear. By using `await`, the programmer tells the compiler where interleaving can happen, avoiding the need to restructure logic to fit the system’s message-passing loop. + +In other languages without these features, developers often need to use advanced patterns like callbacks and event handlers. This low-level, systems-style programming can be powerful but is error-prone, as it breaks high-level logic into scattered events and shared state. + +### Example + +To demonstrate how asynchronous actors work, consider the following example. + +Customers place orders at a pizza restaurant, but the chef can only make one pizza at a time. Orders are taken **[asynchronously](/languages/motoko/fundamentals/actors-async#async--await)**, meaning customers do not have to wait for previous orders to be completed before placing their own. However, each pizza is prepared sequentially. This is representative of an asynchronous actor. + +```motoko no-repl +import Array "mo:core/Array"; +import Text "mo:core/Text"; + +persistent actor PizzaParlor { + var orders : [Text] = []; + + public shared func placeOrder(order : Text) : async Text { + // Use Array.tabulate to create a new array with the additional element + let newOrders = Array.tabulate(orders.size() + 1, func(i) { + if (i < orders.size()) { orders[i] } else { order } + }); + orders := newOrders; + return "Order received: " # order; + }; + + public shared func makePizza() : async Text { + if (orders.size() == 0) { + return "No orders to make."; + }; + + let currentOrder = orders[0]; + // Use Array.filter to remove the first order, assuming orders are unique + orders := Array.filter(orders, func(o) { + not Text.equal(o, currentOrder) + }); + return "Made a delicious " # currentOrder # " pizza!"; + }; + + public query func getOrders() : async [Text] { + return orders; + }; +} +``` + +## `async*` / `await*` + +You can move asynchronous code into a local `async` function and replace repeated code with calls to it. Since these calls return futures, you need to `await` each one to get the result. However, this approach has drawbacks: + +- Each call sends an extra message to the actor. + +- Every call must be awaited, adding overhead. + +- Each `await` suspends execution, increasing chances of interference from other concurrent messages. + +To reduce the overhead and risks of extra `await`s, Motoko provides computation types, written as `async* T`. Like futures (`async T`), computations can represent asynchronous tasks. + +An `async` expression creates a future by starting its execution immediately, while an `async*` expression creates a computation by delaying execution until needed. Similarly, `await` gets the result of a future, and `await*` gets the result of a computation by triggering its next step. + +From a typing perspective, futures and computations are similar, but they behave differently at runtime. A future is a stateful object representing a scheduled asynchronous task, while a computation is an inactive value that describes a task. + +When you use `await` on a future, it suspends the caller until the task finishes. But `await*` on a computation doesn’t suspend the caller; it immediately runs the computation like a normal function call. + +This means that `await*` only causes suspension if the computation’s body itself uses a regular `await`. The `*` indicates that the computation might include zero or more `await` calls and so may be interleaved with other message executions. + +You create an `async*` value by using an `async*` expression, but usually, it’s done by defining a local function that returns an `async*` type. + +To get the result of an `async*` computation, you use `await*`. + +:::danger + +Use `async*` and `await*` carefully. In Motoko, a regular `await` is a commit point. State changes are saved before the function pauses. + +`await*` is not a commit point because the computation it runs may not pause or commit at a predictable time. This means if a trap happens inside an `await*` computation, the actor’s state will roll back to the last commit point before the `await*`, not to the point of the `await*` itself. + +::: + +### Example + +``` motoko no-repl +persistent actor class (Logger : actor { log : Text -> async () }) { + + var logging = true; + + func maybeLog(msg : Text) : async* () { + if (logging) { await Logger.log(msg) }; + }; + + func doStuff() : async () { + // do stuff + await* maybeLog("Log entry #1"); + // do more stuff + await* maybeLog("Log entry #2"); + } +} +``` + +## `try/finally` + +The `try/finally` construct ensures that a block of code in the `finally` clause executes regardless of whether an exception occurs in the `try` block. This is particularly useful for cleanup operations, such as logging or finalizing an action, ensuring that necessary steps are taken even if an error interrupts execution. + +In the `placeOrder` function below: + +- The `try` block processes an order and appends it to the `orders` array. +- The `finally` block logs that the order has been processed, ensuring that this message is always printed, whether the function succeeds or fails. + +```motoko no-repl +public shared func placeOrder(order : Text) : async Text { + try { + Debug.print("Processing order: " # order); + + let newOrders = Array.tabulate( + orders.size() + 1, + func(i) { + if (i < orders.size()) {orders[i]} else {order} + } + ); + + orders := newOrders; + return "Order received: " # order + } finally { + Debug.print("Order processed : " # order) + }; + +}; +``` + +## `try/catch/finally` + +A `catch` block can be inserted inside a `try/finally` expression to catch an error. + +```motoko no-repl + try { + // Code that might throw an error + } catch (e) { + // Handle the error + } finally { + // Cleanup code that always runs + } +``` + +When `catch` is used, the `finally` clause is optional. The `catch` block only catches errors in certain scenarios: + +1. Explicit throws: When code in the `try` block explicitly throws an error using the `throw` keyword: + +```motoko no-repl + try { + throw Error.reject("Intentional error"); + } catch (e) { + // This will catch the explicitly thrown error + } +``` + +2. Errors from awaited calls: If an `await` expression in the `try` block returns an error: + +```motoko no-repl + try { + let result = await someAsyncFunction(); // If this returns an error + } catch (e) { + // The error will be caught here + } +``` + +`catch` blocks **do not** catch errors in the following scenarios: + +1. Local traps. +2. Pre-await traps in async functions. +3. Traps after `await`. + + +Logo diff --git a/docs/languages/motoko/fundamentals/advanced-types.md b/docs/languages/motoko/fundamentals/advanced-types.md new file mode 100644 index 00000000..b52b7cbe --- /dev/null +++ b/docs/languages/motoko/fundamentals/advanced-types.md @@ -0,0 +1,284 @@ +--- +sidebar_position: 12 +description: "Motoko language documentation" +title: "Advanced types" +--- + +Advanced type features enable more flexible and expressive type definitions, including structural equality, generic types, subtyping, recursive types, and type bounds. + +## Structural equality + +Structural equality determines whether two values are equal based on their contents. This applies to immutable data structures, such as [records](/languages/motoko/fundamentals/records) and [variants](/languages/motoko/fundamentals/variants), but does not apply to mutable structures for safety reasons. + +```motoko +type Point = { x : Int; y : Int }; + +let p1 : Point = { x = 1; y = 2 }; +let p2 : Point = { x = 1; y = 2 }; + +p1 == p2; // true (structural equality) +``` + +Even though `p1` and `p2` are distinct objects, they are considered equal because they have the same structure and values. + +This remains true even if different fields are added to the point values, since the `==` on `Point` values only considers the `x` and `y` fields and ignores other fields. + +```motoko +type Point = { x : Int; y : Int }; + +let p1 : Point = { x = 1; y = 2; z = 3 }; +let p2 : Point = { x = 1; y = 2; z = 4; c = "Red"; }; + +p1 == p2; // true (structural equality at type `Point`) +``` + +## Generic types + +Generic types are used to define type parameters that work with multiple data types, commonly used in [functions](/languages/motoko/fundamentals/functions), [classes](/languages/motoko/fundamentals/objects-classes), and data structures. + +```motoko +// Generic function +func identity(x : T) : T { + return x; +}; + +identity(42); // num is Nat +``` + +A generic class can store any type while maintaining type safety: + +```motoko +class Box(value : T) { + public func open() : T { value }; +}; + +let intBox = Box(10); +intBox.open(); +``` + +## Recursive types + +Recursive types allow a type to refer to itself, enabling the creation of nested structures while maintaining type safety. The core package utilizes recursive types to define linked lists. + +```motoko no-repl +type List = ?(Nat, List); +``` + +This defines a recursive type for representing a linked list of natural number. Each list is either: + +- `null`, representing the empty list. + +- `?(head, tail)`, where `head` is a `Nat` and `tail` is another `List`. + +```motoko +?(1, ?(2, ?(3, null))) // A list: 1 → 2 → 3 +``` + +To generalize this structure and support values of any type, we introduce a parameterized type: + +```motoko no-repl +type List = ?(T, List); +``` + +This defines a generic linked list, where `T` can be any type (`Nat`, `Text`, `Blob`, or a custom type). + +### Manually reversing a linked list + +Reversing a linked list involves iterating through the list and prepending each element to a new list. This approach demonstrates list traversal without using `List.reverse` library function. + +Non-parameterized type: + +```motoko name=List +// Lists of naturals +type List = ?(Nat, List); + +// Reverses List +func reverseNat(l : List) : List { + var current = l; + var rev : List = null; + + loop { + switch (current) { + case (?(head, tail)) { + rev := ?(head, rev); + current := tail; + }; + case (null) { + return rev; + }; + }; + }; +}; +``` + +```motoko _include=List no-repl +let numbers : List = ?(1, ?(2, ?(3, null))); +reverseNat(numbers); // ?(3, ?(2, ?(1, null))) +``` + +Parameterized: + +```motoko name=GenList +// Lists of naturals +type List = ?(T, List); + +// Reverses List +func reverse(l : List) : List { + var current = l; + var rev : List = null; + loop { + switch (current) { + case (?(head, tail)) { + rev := ?(head, rev); + current := tail; + }; + case (null) { + return rev; + }; + }; + }; +}; +``` + +These type and function definitions generalize the previous code to work not just on lists of `Nat`s, but on lists of `T` values, for any type `T`. + +You can reverse a list of numbers. + +``` motoko _include=GenList no-repl +let numbers : List = ?(1, ?(2, ?(3, null))); +reverse(numbers); // ?(3, ?(2, ?(1, null))) +``` +But you can also reverse a list of characters: + +```motoko _include=GenList no-repl + +let chars : List = ?('a', ?('b', ?('c', null))); +reverse(numbers); // ?('c', ?('b', ?('a', null))) +``` + +Notice how generic types and generic functions complement each other. + +## Type bounds + +Generic types can use subtype constraints, ensuring that any type used in a generic function meets specific structural or concrete type requirements. + +These constraints are enforced at compilation. This guarantees that the necessary properties or operations are available when the function is used, eliminating certain classes of runtime errors. + +Although the concept of type bounds is often associated with [inheritance-based polymorphism](https://www.codecademy.com/learn/learn-java/modules/learn-java-inheritance-and-polymorphism/cheatsheet) in other languages, Motoko uses structural typing. This means that the subtype relationship is determined by the structure of the types rather than an explicit inheritance hierarchy. **Motoko does not support inheritance**. + +This approach balances the flexibility of generic programming with the safety of compile-time checks, enabling the creation of generic functions that operate on a range of types while still enforcing specific structural or type constraints. + + +The following examples illustrate this behavior: + +```motoko +func printName(x : T): Text { + debug_show(x.name); +}; + +let ghost = { name = "Motoko"; age = 30 }; +printName(ghost); // Allowed since 'ghost' has a 'name' field. +``` + +In the example above, `T <: { name : Text }` requires that any type used for `T` must be a subtype of the [record](/languages/motoko/fundamentals/records) `{ name : Text }`, that is, it must have at least a `name` field of type [`Text`](https://mops.one/core/docs/Text). Extra fields are permitted, but the `name` field is mandatory. + +Type bounds are not limited to records. +In general, the notation `T <: A` in a parameter declaration mandates that any type provided for type parameter `T` must be a subtype of the specified type `A`. +For example, it is possible to constrain a generic type to be a subtype of a primitive type. + +```motoko name=max +func max(x : T, y : T) : T { + if (x <= y) y else x +}; +max(-5, -10); // returns -5 : Int +``` + +Here, `T <: Int` constrains `T` to be a subtype of [`Int`](https://mops.one/core/docs/Int), ensuring that arithmetic operations are valid. + +But the function can also be used to return the maximum of two `Nat`s and still produce a `Nat` (not an `Int`). + +```motoko _include=max no-repl +max(5, 10); // returns 10 : Nat +``` + +## Actor reference expression + + +The *actor reference* expression `actor ` compute a reference to an actor from a text argument ``, the textual encoding of a canister id. The expression is typically combined with an (actor) type annotation, `actor : ` that declares the expected type of the actor reference. The argument can either be a text literal, identifier, or, when enclosed in parentheses, a more complicated expression that computes a textual id. + +A simple example of using actor references is to access the management canister with textual address `"aaaaa-aa"`. Amongst other things, it has a method `raw_rand` for generating cryptographically random bytes as a `Blob`. + +```motoko +persistent actor Coin { + public func flip() : async Bool { + let managementCanister = actor "aaaaa-aa" : actor { raw_rand : () -> async Blob }; + let entropy = await managementCanister.raw_rand(); + (entropy[0] & 1) == 1; + }; +} +``` + +A variation computes the textual canister identifier from a given principal. A call to `flipWith(p)` will succeed is called with `Principal.fromBlob("aaaaa-aa")`, but may fail with another argument, if the canister does not exist or does not have a `raw_rand` function: + +```motoko +import Principal "mo:core/Principal"; + +persistent actor Coin { + public func flipWith(principal : Principal) : async Bool { + let canister = actor (Principal.toText(principal)) : actor { raw_rand : () -> async Blob }; + let entropy = await canister.raw_rand(); + (entropy[0] & 1) == 1; + }; +} +``` + +:::caution + +There is currently no way to verify the actual type of the actor is compatible with the declared type. The validity of the actor reference and any type incompatibility will be detected later, on interaction with the actor. +For this reason, you should only use actor references sparingly. It's typically safer to use explicitly imported canisters with their given actor types and avoid using `Text` or `Principal` to represent canisters in your methods (just use actor types instead). + +For example, a safer variant of `flipWith` is: + +```motoko no-repl +persistent actor Coin { + public func flipWith(canister : actor { raw_rand : () -> async Blob }) : async Bool { + let entropy = await canister.raw_rand(); + (entropy[0] & 1) == 1; + }; +} +``` + +This `flipWith` takes a strongly-typed actor, not a weakly-typed `Principal`. + + +Actor type annotations offer flexibility when working with external canisters, but there’s no guarantee that the function signatures will match at runtime. If the signatures don’t align, the calls will fail. + +As another example of using actor reference expressions, we present a simple `Publisher` actor that tracks sets of subscribers by their `Principal` and uses an actor reference expression access the `notify` of each subscriber when a message is `published`: + + + +```motoko no-repl +import Array "mo:core/Array"; +import Principal "mo:core/Principal"; + +actor Publisher { + stable var subscribers : [Principal] = []; + + public shared func subscribe(subscriber : Principal) : async () { + if (Array.find(subscribers, func(s) { s == subscriber }) == null) { + let newSubscribers = Array.tabulate( + subscribers.size() + 1, + func(i) { if (i < subscribers.size()) subscribers[i] else subscriber } + ); + subscribers := newSubscribers; + }; + }; + + public shared func publish(message : Text) : async () { + for (sub in subscribers.vals()) { + let subActor = actor(Principal.toText(sub)) : actor { notify : (Text) -> async () }; + await subActor.notify(message); + }; + }; +}; +``` \ No newline at end of file diff --git a/docs/languages/motoko/fundamentals/basic-control-flow.md b/docs/languages/motoko/fundamentals/basic-control-flow.md new file mode 100644 index 00000000..bb8c2adb --- /dev/null +++ b/docs/languages/motoko/fundamentals/basic-control-flow.md @@ -0,0 +1,310 @@ +--- +sidebar_position: 1 +description: "Motoko language documentation" +title: "Basic control flow" +--- + +In Motoko, code normally executes sequentially, evaluating expressions and declarations in order. +However, certain constructs can alter the flow of control, such as exiting a block early, skipping iterations in a loop, returning a value from a function, or invoking another function. + +# Control flow expressions + +| Construct | Description | +|--------------|---------------| +| `return` | Exits a function and returns a value. | +| `if` | Executes a block if the condition is `true`. | +| `if/else` | Executes different blocks based on a condition. | +| `switch` | [Pattern matching](/languages/motoko/fundamentals/pattern-matching) for variants, options, results, etc. | +| `let-else` | Destructure a pattern and handle the failure case inline. | +| `option block` | Evaluates an expression and wraps the result in an option type, allowing scoped handling of `null` values. | +| `label/break` | Allows exiting loops early. | +| `loop` | Iterates indefinitely | +| `loop ... while` | Iterates until some condition is false | +| `while` | Iterates while a condition is `true`. | +| `for` | Iterates over elements in a collection, terminating when no elements remain. | + +## `return` + +A `return` statement immediately exits a function or `async` block with a result. Unlike `break` or `continue`, which jump to a point within the same function (either to a label or to the innermost loop), `return` does not target a label. Instead, it exits the current function entirely, either returning control to the caller or, in asynchronous contexts, completing a future and resuming the caller that's awaiting the result. + +Consider this function that computes the product of an array of integers. + +```motoko no-repl +func product(numbers : [Int]) : Int { + var prod : Int = 1; + for (number in numbers.vals()) { + prod *= number; + }; + prod; // The implicit result of the block and function +} +``` + +This function doesn't require an explicit `return`. It just returns the result of its body, `prod`. + +However, `prod` will remain `0` once it becomes `0` so you can save some work by using `return` to return from the function early, exiting both the loop and the function with result `0`. + +```motoko no-repl +func product(numbers : [Int]) : Int { + var prod : Int = 1; + for (number in numbers.vals()) { + prod *= number; + if (prod == 0) return 0; // an early return can save work + }; + prod; // The implicit result of the block and function +} +``` + +This also works with asynchronous functions that produce futures: + +```motoko no-repl +func asyncProduct(numbers : [Int]) : async Int { + var prod : Int = 1; + for (number in numbers.vals()) { + prod *= number; + if (prod == 0) return 0; // an early return completes the future + }; + prod; // The implicit result of the block and function +} +``` + +If the expected return type is `()` then you can just write `return` instead of `return ()`. + +## `switch` + +A `switch` expression matches a value against multiple cases and executes the block of code associated with the first matching case. + +```motoko no-repl +import Nat "mo:core/Nat"; + +type HttpRequestStatus = { + #ok: Nat; + #err: Nat; +}; + +func checkStatus(r : HttpRequestStatus) : Text { + switch (r) { + case (#ok successCode) { "Success: " # Nat.toText(successCode) }; + case (#err errorCode ) { "Failure: " # Nat.toText(errorCode) }; + }; +}; +``` + +## `let-else` + +The `let-else` construct allows conditional binding of the variables in a pattern, by attempting to match a value to the pattern. The `else` clause handles the case when the pattern is not a match. It is useful when working with `Result` and optional values (`?T`), enabling concise error handling or early exits when the value is `null`. + +Since the code following the `let` cannot execute without its matching bindings, the `else` clause must have type `None`, typically by diverting control using `return`, `throw`, `break` or `continue`. + +```motoko no-repl +import Nat "mo:core/Nat"; + +type HttpRequestStatus = { + #ok: Nat; + #err: Nat; +}; + +func checkStatus(r : HttpRequestStatus) : Text { + let #ok status = r else return "The request failed!"; + Nat.toText(status) +}; +``` + +:::note +Unlike a `switch`, `let-else` discards any additional error information from non-matching cases, making it less suitable when detailed error handling is needed. The `(#err e)` case is dropped entirely; `e` cannot be inspected or logged. +::: + +## Option block + +These blocks represented as `do ? {...}` allow safe unwrapping of optional values using the postfix operator `!`, which short-circuits and exits the block with `null` if any value is `null`, simplifying code that handles multiple options. The result of the inner block, if any, is returned in an option. + +A simple example uses an option block to concisely add optional number, return `null` when either is `null`. + +```motoko no-repl + // Returns the sum of optional values `n` and `m` or `null`, if either is `null` +func addOpt(n : ?Nat, m : ?Nat) : ?Nat { + do ? { + n! + m! + } +}; +let o1 = addOpt(?5, ?2); // ?7 +let o2 = addOpt(null, ?2); // null +let o3 = addOpt(?5, null); // null +let o4 = addOpt(null, null); // null +``` + +Instead of having to switch on the options `n` and `m` in a verbose manner the use of the postfix operator `!` makes it easy to unwrap their values but exit the block with `null` when either is `null`. + +A more interesting example of option blocks can be found at the end of the section on [switch](/languages/motoko/fundamentals/switch). + +## `label` and `break` + +A `label` assigns a name with an optional type to a block of code that executes like any other block. +The type on the label should indicate the type of the block and defaults to `()` when omitted. + +When a labeled block runs, it evaluates the block to produce a result. +Labels don’t change how the block executes but enable early exits from the block using a `break` to that label. +If the type is not `()` those breaks must have an argument, to use as the result of the labelled expression. + +Just as `return` exits a function early with a result, `break` exits its label early with a result. +Indeed, you can think of `return` as a `break` from the enclosing function. + +```motoko no-repl +func product(numbers : [Int]) : Int { + var prod : Int = 1; + label l for (number in numbers.vals()) { + prod *= number; + if (prod == 0) break l; + }; + prod; // The implicit result of the block and function +} +``` + +If the block produces a non-`()` result, as in this minor refactoring, the `break` should include a value: + +```motoko no-repl +func product(numbers : [Int]) : Int { + label result : Int { + var prod : Int = 1; + for (number in numbers.vals()) { + prod *= number; + if (prod == 0) break result 0; + }; + prod + } +} +``` + +Labels provide fine control over execution, allowing early exits and helping to structure complex logic. + +## `loop` + +A `loop` expression repeatedly executes a block of code (forever). + +```motoko no-repl +import Debug "mo:core/Debug"; +import Nat "mo:core/Nat"; + +var i = 0; +loop { + Debug.print(Nat.toText(i)); + i += 1; +} +``` + +## `loop-while` + +A `loop-while` expression repeatedly executes a block of code (at least once) until the while condition evaluates to `false`. + +```motoko no-repl +import Debug "mo:core/Debug"; +import Nat "mo:core/Nat"; + +var i = 0; +loop { + Debug.print(Nat.toText(i)); + i += 1; +} while (i < 5) +``` + + +## `while` + +A `while` loop repeatedly executes a block of code as long as a specified condition evaluates to `true`. +If the condition is initially `false`, the block is never executed. + +```motoko no-repl +import Debug "mo:core/Debug"; +import Nat "mo:core/Nat"; + +var i = 0; +while (i < 5) { + Debug.print(Nat.toText(i)); + i += 1; +} +``` + +## `for` + +A `for` loop iterates over the elements of an iterator, and object of type `{ next: () -> ?T }`, executing a block of code for each element. + +```motoko no-repl +import Debug "mo:core/Debug"; +import Nat "mo:core/Nat"; + +let numbers = [0, 1, 2, 3, 4]; +for (num in numbers.vals()) { + Debug.print(Nat.toText(num)); +} +``` + +It will run forever if the iterator's `next` method never returns `null`. + +## `continue` + +A `continue` expression skips the remainder of the current iteration in a loop and immediately proceeds to the next iteration. `continue` without a label continues the innermost loop. When a loop is labeled with a label `l`, then `continue l` continues the loop labeled `l`. This works within `while`, `for`, `loop`, or `loop-while` expressions. + +For example, computing the product we can skip a multiplication when the number is `1`: + +``` motoko no-repl +func product(numbers : [Int]) : Int { + var prod : Int = 1; + for (number in numbers.vals()) { + if (number == 1) continue; + prod *= number; + }; + prod; +} +``` + +When you have nested loops and need to continue a specific outer loop, you can use a label: + +``` motoko no-repl +func product(numbers : [Int]) : Int { + var prod : Int = 1; + label l for (number in numbers.vals()) { + if (number == 1) continue l; + prod *= number; + }; + prod; +} +``` + +## Loop exits + +You can always exit a `loop`, `loop-while`, `while` or `for` loop using `break`. +`break` without a label exits the innermost loop. +If a loop is labeled with a label `l`, then `break l` exits the loop labeled `l`. +You can also exit any loop in a function using `return` or (in an asynchronous function) `throw`. + +## Function calls + +A function call executes a function by passing arguments and receiving a result. In Motoko, function calls can be synchronous (executing immediately within the same [canister](https://internetcomputer.org/docs/building-apps/essentials/canisters)) or [asynchronous](/languages/motoko/fundamentals/actors-async#async--await) (message passing between canisters). Asynchronous calls use `async`/`await` and are essential for inter-canister communication. + +```motoko no-repl +persistent actor { + + func product(numbers : [Int]) : Int { + var prod : Int = 1; + for (num in numbers.values()) { + prod += num; + if (prod == 0) return 0; // an early return can save work + }; + prod; + }; + + public func asyncProduct(numbers : [Int]) : async Int { + return product(numbers); // function call + }; + +} +``` + + + +Execution begins in `asyncProduct()`, where the local function `product()` is invoked, transferring control to its logic. Inside `product()`, the numbers are processed one by one. If a zero is encountered, a `return` statement immediately exits the call to `product()` and returns 0. +Control then flows back to `asyncProduct()`, which just returns the result, completing the asynchronous call. + +Function calls temporarily interrupt the normal sequential flow by shifting execution to a separate block of logic. Once the called function completes, control resumes at the point where the call was made, continuing with its result. + + + diff --git a/docs/languages/motoko/fundamentals/blocks.md b/docs/languages/motoko/fundamentals/blocks.md new file mode 100644 index 00000000..f83f630f --- /dev/null +++ b/docs/languages/motoko/fundamentals/blocks.md @@ -0,0 +1,69 @@ +--- +sidebar_position: 4 +description: "Motoko language documentation" +title: "Block expressions" +--- + +A block expression in Motoko is a sequence of declarations enclosed in `{ ... }`. +Since every expression is also a declaration, the sequence can include expressions. +Intermediate expressions, that produce values other than `()`, must be prefixed with `ignore`. + +Blocks are used to group multiple operations, define local variables, and structure code for clarity. + +Block expressions are typically used to define function bodies and the bodies of `async` expressions. +They can also be used as branches in conditional expressions and as the bodies of cases in switches and the blocks of `try-catch-finally` expressions. +Since blocks enclose declarations, they define new scopes for locally defined variables and types. + +The last declaration in a block, which might be an expression, determines the block’s result. If no meaningful final declaration is present, the block returns `()`. + +## Block expressions in functions + +Every function in Motoko contains a block expression that defines its body and behavior. + +```motoko no-repl +// The function body is a block expression that returns the result of the last expression. +shared func add(x : Nat, y : Nat) : async Nat { + let sum : Nat = x + y; + sum; +}; + +// Example of using a block expression with conditional logic: +func classify(n : Int) : Text { + if (n > 0) { + "Positive" + } else if (n < 0) { + "Negative" + } else { + "Zero" + } // The last evaluated branch determines the return value. +}; +``` + +### `do` blocks + +Blocks are not limited to functions; they can be used anywhere an expression is expected by prefixing the block with `do`: + +```motoko no-repl +let result : Nat = do { + let x : Nat = 10; + let y : Nat = 5; + x * y // This value is returned and assigned to `result` +}; +``` + + +The `do {}` expression in Motoko can be used to enter a new scope and make some local declarations before producing a value. + + +A `do {}` block can also just return `()` and be evaluated for its side effect: + +```motoko no-repl +do { + let x : Nat = 10; + let y : Nat = 5; + Debug.print("Adding " # debug_show(x) # " and " # debug_show(y)); + let sum : Nat = x + y; + Debug.print("Result: " # debug_show(sum)); // unit `()` return type +}; +``` + diff --git a/docs/languages/motoko/fundamentals/characters-text.md b/docs/languages/motoko/fundamentals/characters-text.md new file mode 100644 index 00000000..0da6c325 --- /dev/null +++ b/docs/languages/motoko/fundamentals/characters-text.md @@ -0,0 +1,120 @@ +--- +sidebar_position: 5 +description: "Motoko language documentation" +title: "Characters & text" +--- + +## Characters + +The `Char` type in Motoko represents a single Unicode character delimited with a single quotation mark (`'`). + +```motoko +let letter : Char = 'A'; +let symbol : Char = '✮'; + +// Comparing characters +'I' == 'i' // False +``` + + +:::note [Iter](https://mops.one/core/docs/Iter) +An `Iter` is an object that sequentially produces values of specified type `T` until no more values remain. +::: +``` motoko +import Char "mo:core/Char"; + +func reverse(t: Text) : Text { + var result = ""; + for (c in t.chars()) { + result := Char.toText(c) # result + }; + result; +}; + +reverse("Motoko"); +``` + +The operator `#` concatenates two `Text` values. + +```motoko +import Text "mo:core/Text"; +import Iter "mo:core/Iter"; +import Char "mo:core/Char"; + +persistent actor Alternator { + + // Turn text into an iterator of Char + func textToChars(t: Text) : Iter.Iter { + t.chars(); + }; + + // Alternate capitalization + public func alternateCaps(t: Text) : async Text { + let chars = textToChars(t); + var index = 0; + // Apply a case function to each char + let modified = Iter.map(chars, func(c: Char) : Text { + let charAsText = Char.toText(c); + let transformedText = + if (index % 2 == 0) { + Text.toUpper(charAsText) + } else { + Text.toLower(charAsText) + }; + index += 1; + transformedText; + }); + + return Text.join("", modified); + }; +}; +``` + +:::note[Conversions] + +- `Char` can be converted to a single-character `Text` using `Char.toText(c)`. +- `Char` can be converted to its 32-bit Unicode scalar value using `Char.toNat32(c)`. +- A `Char` can be converted from a 32-bit Unicode scalar value using `Char.fromNat32(n)` (the function traps on invalid codes). +::: + +## Text + +Strings of characters, familiar from other languages, are called **text** in Motoko, and represented using the [`Text`](https://mops.one/core/docs/Text) type. A text value is an immutable sequence of Unicode characters delimited with a double quotation mark (`"`). + +```motoko +let greeting : Text = "Hello, world!"; +``` + +The `#` operator concatenates two `Text` values: + +``` motoko +// Concatenating text + +"ICP " # "❤️" # " Motoko" // "ICP ❤️ Motoko" +``` + +`t.size()` can be used to return the number of characters in the text `t`. + +```motoko +"abc".size() == 3 +``` + +`t.chars()` returns an iterator enumerating the characters in `t`. For example: + +```motoko +import Char "mo:core/Char"; +import Debug "mo:core/Debug"; + +for (c in "abc".chars()) { + Debug.print(Char.toText(c)); +} +``` + +Text values can be compared using "==", "<" and all the other relational operators. + +## Resources + +- [`Char`](https://mops.one/core/docs/Char) +- [`Text`](https://mops.one/core/docs/Text) +- [`Iter`](https://mops.one/core/docs/Iter) + diff --git a/docs/languages/motoko/fundamentals/class-declarations.md b/docs/languages/motoko/fundamentals/class-declarations.md new file mode 100644 index 00000000..094bfd29 --- /dev/null +++ b/docs/languages/motoko/fundamentals/class-declarations.md @@ -0,0 +1,169 @@ +--- +sidebar_position: 4 +description: "Motoko language documentation" +title: "Class declarations" +--- + +A class in Motoko serves as a blueprint for creating [objects](/languages/motoko/fundamentals/object-declaration) that encapsulate both [state](/languages/motoko/fundamentals/state) and behavior. It defines fields to hold data and methods to operate on that data. Unlike records and plain objects, classes support constructors, allowing developers to initialize each instance with unique values at creation time. + +Classes in Motoko are not the same as classes in other object oriented programming languages, but they serve the same purpose. Motoko also doesn’t have a `this` or `self` keyword because you can simply call other methods directly by name or name the entire object using an identifier of your choice. + +Use a class when you need to: +- Create multiple objects with the same fields and methods. +- Encapsulate state and behavior inside an object. +- Simulate object orientated programming-like design patterns. + +Classes are particularly useful when using multiple objects with similar structures but different initial states. You can think of classes as a template for creating objects. You define fields and methods, and then create new instances by calling the class like a function. + +## Defining a class + +A class in Motoko defines both: + +- A constructor for creating instances, which includes: + - Fields to store data. + - Methods to perform operations on that data. +- A type that describes the interface of the instance, including its available methods. + +Motoko also supports generic classes, which allow abstraction over types. This enables the creation of reusable, type-safe components that can work with a variety of data types while maintaining strong compile-time guarantees. + +```motoko no-repl +import Order "mo:core/Order"; // Required to reference O.Order and its variants + +// A generic comparator class for ordering elements +class Comparator(compare : (T, T) -> Order.Order) { + public func lessThan(a : T, b : T) : Bool { + compare(a, b) == #less; + }; + + public func equal(a : T, b : T) : Bool { + compare(a, b) == #equal; + }; + + public func greaterThan(a : T, b : T) : Bool { + compare(a, b) == #greater; + }; +}; + +``` + +This declaration defines: + +- A constructor: `Comparator : ((K, K) -> Order) -> Comparator`. +- A generic type: `Comparator` that provides comparison methods. + +## Creating instances + +Creating an instance is when a class constructor is used to produce a new object with its own state and behavior based on the class definition. + +```motoko no-repl +class Counter(init : Nat) { + var count : Nat = init; + + public func inc() : Nat { + count += 1; + count + }; +}; + +// Creating an instance of the class +let myCounter = Counter(0); + +// Using the instance +myCounter.inc(); // returns 1 +``` + +The class declaration syntax also lets you: +* Check that the class conforms to some interface, expressed as an object type. +* Define a self-identifier to refer to the entire object. + +```motoko no-repl +type Reset = { reset : () -> () }; + +class Counter(init : Nat) : Reset = this { + var count : Nat = init; + + public func inc() : Nat { + count += 1; + count + }; + + public func getThis() : Counter { this }; + + public func reset() { count := 0 }; +}; +``` + +This extended `Counter` class checks that the implementation matches interface `Reset` and names this parameter `self`. + +## Actor classes + +Actor classes enable you to create networks of actors programmatically. These classes must be defined in separate source files. + +```motoko no-repl title="Counter.mo" +persistent actor class Counter(init : Nat) { + var count : Nat = init; + + public func inc() : async Nat { + count += 1; + count; + }; + + public func get() : async Nat { + count; + }; +} +``` + +This defines a `Counter` actor class with: + +- A mutable variable `count`. + +- A method `inc` that increases `count` and returns the new value. + +- A method `get` that returns the current count. + +Then, in another file you can create an instance of this actor class: + + +```motoko no-repl title="CallCounter.mo" +import Counter "./Counter"; + +persistent actor { + + public func test() : async () { + let counter = await (with cycles = 1_000_000_000_000) Counter.Counter(0); + + let newCount = await counter.inc(); + + Debug.print("Count is now: " # Nat.toText(newCount)); + + let currentCount = await counter.get(); + Debug.print("Current count: " # Nat.toText(currentCount)); + } +} +``` + +Unlike object classes, actor class constructors are asynchronous. The constructor returns a future that contains the instance. You obtain the instance itself using `await`. + +:::note + +On ICP, calls to a class constructor must be provisioned with cycles to pay for the creation of a principal. See [Cycles](https://mops.one/core/docs/Cycles) for instructions on how to add cycles to a call using the imperative `Cycles.add(cycles)` function. + +::: + +### Configuring and managing actor class instances + +On ICP, the primary constructor of an imported actor class always creates a new principal and installs a fresh instance of the class as the code for that principal. + +To offer more control over actor class installation, Motoko provides each imported actor class with a secondary constructor. This constructor takes an additional first argument that specifies the desired installation mode. + +This advanced constructor is only available via special `system` syntax, highlighting its low-level nature. + +Using this `system` syntax, developers can: + +- Specify initial canister settings (e.g., an array of controllers). +- Manually install, upgrade, or reinstall canisters. +- Access lower-level canister management features provided by ICP. + +[Learn more about actor class management](https://docs.motoko.org#actor-class-management). + diff --git a/docs/languages/motoko/fundamentals/comments.md b/docs/languages/motoko/fundamentals/comments.md new file mode 100644 index 00000000..b4d720dc --- /dev/null +++ b/docs/languages/motoko/fundamentals/comments.md @@ -0,0 +1,50 @@ +--- +sidebar_position: 10 +description: "Motoko language documentation" +title: "Comments" +--- + +Motoko supports single-line, multi-line, and nested comments. + +## Single line + +Use `//` for comments that extend to the end of a line. + +```motoko no-repl +// This is a single-line comment +``` + +Use `///` for function or module documentation (also known as "doc comments"). Module documentation can be exported into documentation files such as Markdown or HTML using [mo-doc](https://docs.motoko.org). + +```motoko no-repl +/// Returns the sum of two integers. +func add(a : Int, b : Int) : Int { + a + b +} +``` + +## Multi-line + +Use `/* ... */` for block comments spanning multiple lines. + +```motoko no-repl +/* This is a + multi-line comment */ +``` + +## Nested + +Multi-line comments can be nested within each other. + +```motoko no-repl +/* Outer comment + /* Nested comment */ + End of outer comment */ +``` + +## Resources + +- [Comment style guide](https://docs.motoko.org#comments) + +- [Generating Motoko documentation](https://docs.motoko.org) + diff --git a/docs/languages/motoko/fundamentals/compatibility.md b/docs/languages/motoko/fundamentals/compatibility.md new file mode 100644 index 00000000..aac18957 --- /dev/null +++ b/docs/languages/motoko/fundamentals/compatibility.md @@ -0,0 +1,481 @@ +--- +sidebar_position: 4 +description: "Motoko language documentation" +title: "Verifying upgrade compatibility" +--- + + + +When upgrading a canister, it is important to verify that the upgrade can proceed without: + +- Introducing an incompatible change in stable declarations. +- Breaking clients due to a Candid interface change. + +`dfx` checks these properties statically before attempting the upgrade. +Moreover, with [enhanced orthogonal persistence](/languages/motoko/fundamentals/orthogonal-persistence-enhanced), Motoko rejects incompatible changes of stable declarations. + +## Upgrade example + +The following is a simple example of how to declare a stateful counter: + +``` motoko no-repl file=../../examples/count-v1.mo +``` + +Importantly, in this example, when the counter is upgraded, its state is preserved and the counter will resume from its last value before the upgrade. +This is because actor variables are by default `stable`, meaning their state is persisted across upgrades. +The above actor is equivalent to using an explicit `stable` declaration: + +``` motoko no-repl file=../../examples/count-v1stable.mo +``` + +Sometime, you won't want an actor field to be preserved, either because it contains a value tied to the current version (say the version number), or +because it has a non-`stable` type that cannot be stored in stable field (an object with methods, for example). +In that case, you can declare the field transient: + + +``` motoko no-repl file=../../examples/count-v0transient.mo +``` + +With the `transient` declaration, the state will always restart from `0`, even after an upgrade. + +## Evolving the stable declarations + +Changing counter from `Nat` to `Int` is a compatible change in stable declarations. The counter value is retained during the upgrade. + +``` motoko no-repl file=../../examples/count-v2.mo +``` + +## Stable type signatures + +A stable type signature describes the stable content of a Motoko actor. +You can think of this as the interior interface of the actor, that it presents to its future upgrades. + +For example, `v1`'s stable types: + +``` motoko no-repl file=../../examples/count-v1.most +``` + +An upgrade from `v1` to `v2`'s stable types consumes a [`Nat`](https://mops.one/core/docs/Nat) as an [`Int`](https://mops.one/core/docs/Nat), which is valid because `Nat <: Int`, that is, `Nat` is a subtype of `Int`. + +``` motoko no-repl file=../../examples/count-v2.most +``` + +## Evolving the Candid interface + +In this extension of the interface, old clients remain satisfied, while new ones get extra features such as the `decrement` function and the `read` query in this example. + +``` motoko no-repl file=../../examples/count-v3.mo +``` + +## Dual interface evolution + +An upgrade is safe provided that both the Candid interface and stable type signatures remain compatible: +* Each stable variable must either be newly declared, or re-declared at a stable supertype of its old type. A stable supertype is any supertype that + does not involve promotion to `Any` or dropping object fields. +* The Candid interface evolves to a subtype. + +Consider the following four versions of the counter example: + +Version `v0` with Candid interface `v0.did` and stable type interface `v0.most`: + +```candid +service : { + increment: () -> (); +} +``` + +``` motoko no-repl file=../../examples/count-v0.most +``` + +Version `v1` with Candid interface `v1.did` and stable type interface `v1.most`, + +```candid +service : { + increment: () -> (); +} +``` + +``` motoko no-repl file=../../examples/count-v1.most +``` + +Version `v2` with Candid interface `v2.did` and stable type interface `v2.most`, + +```candid +service : { + increment: () -> (); +} +``` + +``` motoko no-repl file=../../examples/count-v2.most +``` + +Version `v3` with Candid interface `v3.did` and stable type interface `v3.most`: + +```candid +service : { + decrement: () -> (); + increment: () -> (); + read: () -> (int) query; +} +``` + +``` motoko no-repl file=../../examples/count-v3.most +``` + +## Incompatible upgrade + +Let's take a look at another example where the counter's type is again changed, this time from [`Int`](https://mops.one/core/docs/Int) to [`Float`](https://mops.one/core/docs/Float): + +``` motoko no-repl file=../../examples/count-v4.mo +``` + +This version is neither compatible to stable type declarations, nor to the Candid interface. +- Since `Int {count : Nat; header : Text}; + "01_AddEmail" : {} -> {email : Text}; + "02_CountToInt" : (old : {count : Nat}) -> {count : Int} +} +actor { + stable count : Int; + stable email : Text; + stable header : Text +}; +``` + +The chain section (enclosed in braces before the `actor` keyword) lists each migration module by its filename (without the `.mo` extension), in ascending lexicographic order. Each entry shows the migration function's type: input fields on the left of `->` and output fields on the right. Migrations that do not consume any fields show `{}` as input. Migrations that consume fields name their parameter (e.g., `old`) and list the consumed field types. + +The `actor` section after the chain lists the final stable fields, just like a Version 1.0.0 signature. + +### How compatibility is checked + +When upgrading from one version to another, `dfx` and `moc --stable-compatible` compare the old and new stable signatures: + +- **Old Version 4.0.0 to new Version 4.0.0:** The post-signature (final `actor` fields) of the old code must be compatible with the pre-signature of the new code. The pre-signature of the new code is derived by walking backward through its migration chain: the last unapplied migration determines which fields must be present. Migrations that were already applied (present in the old signature's chain) are skipped automatically. + +- **Old Version 1.0.0 or 3.0.0 to new Version 4.0.0:** The post-signature of the old code is checked against the pre-signature derived from the new chain, starting from the first migration not yet applied. This allows adopting enhanced multi-migration from a canister that was previously using either no migration or a single migration function. + +- **Old Version 4.0.0 to new Version 1.0.0 or 3.0.0:** This is **not allowed**. Once a canister adopts enhanced multi-migration, it cannot revert to the older migration styles. The compiler rejects such upgrades with an error. + +### Example: evolving enhanced signatures + +Consider a canister that starts with a single migration and then adds more over time. + +After the initial deployment with one migration (`00_Init`), the stable signature is: + +``` +// Version: 4.0.0 +{ + "00_Init" : {} -> {a : Nat} +} +actor { + stable a : Nat +}; +``` + +After a second deployment that adds a new field via migration `01_AddB`: + +``` +// Version: 4.0.0 +{ + "00_Init" : {} -> {a : Nat}; + "01_AddB" : {} -> {b : Int} +} +actor { + stable a : Nat; + stable b : Int +}; +``` + +The upgrade from the first signature to the second is valid: the old actor's post-signature `{a : Nat}` is compatible with the new code's pre-signature at migration `01_AddB`, which requires no fields from the old actor (its input is `{}`), and carries `a : Nat` through unchanged. + +After a third deployment that changes `b` from `Int` to `Bool`: + +``` +// Version: 4.0.0 +{ + "00_Init" : {} -> {a : Nat}; + "01_AddB" : {} -> {b : Int}; + "02_ChangeBType" : (old : {b : Int}) -> {b : Bool} +} +actor { + stable a : Nat; + stable var b : Bool +}; +``` + +The upgrade from the second to the third signature is valid: migration `02_ChangeBType` consumes `b : Int` from the old state, which is present and compatible, and produces `b : Bool`. + +## Upgrade tooling + +`dfx` incorporates an upgrade check. For this purpose, it uses the Motoko compiler (`moc`) that supports: + +- `moc --stable-types …​`: Emits stable types to a `.most` file. + +- `moc --stable-compatible
 `: Checks two `.most` files for upgrade compatibility.
+
+Motoko embeds `.did` and `.most` files as Wasm custom sections for use by `dfx` or other tools. The `--stable-compatible` check works across all [stable signature versions](#stable-signature-versions) (1.0.0, 3.0.0, and 4.0.0), so `dfx` can verify compatibility regardless of the migration style used by either version.
+
+To upgrade e.g. from `cur.wasm` to `nxt.wasm`, `dfx` checks that both the Candid interface and stable variables are compatible:
+
+```
+didc check nxt.did cur.did  // nxt <: cur
+moc --stable-compatible cur.most nxt.most  // cur <<: nxt
+```
+
+Using the versions above, the upgrade from `v3` to `v4` fails this check:
+
+```
+> moc --stable-compatible v3.most v4.most
+(unknown location): Compatibility error [M0170], stable variable state of previous type
+  var Int
+cannot be consumed at new type
+  var Float
+```
+
+With [enhanced orthogonal persistence](/languages/motoko/fundamentals/orthogonal-persistence-enhanced), compatibility errors of stable variables are always detected in the runtime system and if failing, the upgrade is safely rolled back.
+
+:::danger
+With [classical orthogonal persistence](/languages/motoko/fundamentals/orthogonal-persistence-classical), however, an upgrade attempt from `v2.wasm` to `v3.wasm` is unpredictable and may lead to partial or complete data loss if the `dfx` warning is ignored.
+:::
+
+## Adding record fields
+
+A common, real-world example of an incompatible upgrade can be found [on the forum](https://forum.dfinity.org/t/questions-about-data-structures-and-migrations/822/12?u=claudio/).
+
+In that example, a user was attempting to add a field to the record payload of an array, by upgrading from stable type interface:
+
+``` motoko no-repl file=../../examples/Card-v0.mo
+```
+
+to *incompatible* stable type interface:
+
+``` motoko no-repl file=../../examples/Card-v1.mo
+```
+
+### Problem
+
+When trying this upgrade, `dfx` issues the following warning:
+
+```
+Stable interface compatibility check issued an ERROR for canister ...
+Upgrade will either FAIL or LOSE some stable variable data.
+
+(unknown location): Compatibility error [M0170], stable variable map of previous type
+  var [(Nat32, Card)]
+cannot be consumed at new type
+  var [(Nat32, Card__1)]
+
+Do you want to proceed? yes/No
+```
+It is recommended not to continue, as you will lose the state in older versions of Motoko that use [classical orthogonal persistence](/languages/motoko/fundamentals/orthogonal-persistence-classical).
+Upgrading with [enhanced orthogonal persistence](/languages/motoko/fundamentals/orthogonal-persistence-enhanced) will trap and roll back, keeping the old state.
+
+Adding a new record field to the type of existing stable variable is not supported. The reason is simple: the upgrade would need to supply values for the new field out of thin air. In this example, the upgrade would need to conjure up some value for the `description` field of every existing `card` in `map`. Moreover, allowing adding optional fields is also a problem, as a record can be shared from various variables with different static types, some of them already declaring the added field or adding a same-named optional field with a potentially different type (and/or different semantics).
+
+To resolve this issue, some form of  [explicit data migration](#explicit-migration) is needed.
+
+
+There are two solutions: using a sequence of simple upgrades, or the second, recommended solution, that uses a single upgrade with a migration function.
+
+### Solution 1: Using two plain upgrades
+
+1. You must keep the old variable `map` with the same structural type. However, you are allowed to change type alias name (`Card` to `OldCard`).
+2. You can introduce a new variable `newMap` and copy the old state to the new one, initializing the new field as needed.
+3. Then, upgrade to this new version.
+
+``` motoko no-repl file=../../examples/Card-v1a.mo
+```
+
+4. **After** you have successfully upgraded to this new version, you can upgrade once more to a version, that drops the old `map`.
+
+
+``` motoko no-repl file=../../examples/Card-v1b.mo
+```
+
+`dfx` will issue a warning that `map` will be dropped.
+
+Make sure you have previously migrated the old state to `newMap` before applying this final reduced version.
+
+```
+Stable interface compatibility check issued a WARNING for canister ...
+(unknown location): warning [M0169], stable variable map of previous type
+  var [(Nat32, OldCard)]
+ will be discarded. This may cause data loss. Are you sure?
+```
+
+### Solution 2: Using a migration function and single upgrade
+
+Instead of the previous two step solution, you can upgrade in one step using a migration function.
+
+1. Define a migration module and function that transforms the old stable variable, at its current type, into the new stable variable at its new type.
+
+
+``` motoko no-repl file=../../examples/CardMigration.mo
+```
+
+2. Specify the migration function as the migration expression of your actor declaration:
+
+
+``` motoko no-repl file=../../examples/Card-v1c.mo
+```
+
+**After** you have successfully upgraded to this new version, you can also upgrade once more to a version that drops the migration code.
+
+
+``` motoko no-repl file=../../examples/Card-v1d.mo
+```
+
+However, removing or adjusting the migration code can also be delayed to the next, proper upgrade that fixes bugs or extends functionality.
+
+Note that with this solution, there is no need to rename `map` to `newMap` and the migration code is nicely isolated from the main code.
+
diff --git a/docs/languages/motoko/fundamentals/conditionals.md b/docs/languages/motoko/fundamentals/conditionals.md
new file mode 100644
index 00000000..5a5122cf
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/conditionals.md
@@ -0,0 +1,85 @@
+---
+sidebar_position: 3
+description: "Motoko language documentation"
+title: "Conditionals"
+---
+
+Conditionals in Motoko come in two forms: **if-expressions** and **if-statements**.
+
+## `if-else`
+
+An `if-else` expression, `if   else `, has three parts:
+
+1. A condition `` that evaluates to a boolean value.
+2. Two branches `` and ``. These branches can be simple expressions or blocks `{ ... }`.
+
+If the condition is `true`, the first branch `` is evaluated to produce the result of the `if-else`.
+If the conditions is `false`, the second branch  ``  is evaluated to produce the result of `if-else`.
+Only one of the branches is evaluated.
+
+The type of the`if-else` is the type of `` and `` if they have the same type; otherwise, it is a more general type that is a supertype of their types.
+
+For example, you might use an `if-else` to choose a label based on a value.
+
+```motoko no-repl
+let x : Int = 1;
+
+let identity : Text =
+  if (x == 1) {
+    "x is 1"
+  } else {
+    "x is not 1"
+  }; // Produces a value
+```
+
+The result of the `if-else` is assigned to `identity`. Here, both branches have the same type ([`Text`](https://mops.one/core/docs/Text) in this case) as does the entire `if-else`.
+
+``` motoko no-repl
+let n : Nat = 0;
+let parity = if (n % 2 == 0) #even else #odd;
+```
+Here, the first branch has type `{#even}` and the second branch has type `{#odd}`. These types are different but they have a common supertype `{#even; #odd}`. The type of the `if-else` is then `{#even; #odd}`.
+
+Motoko will infer the common supertype for you, choosing the most specific one possible. If the types are inconsistent and only have the useless common supertype `Any`, Motoko will issue a warning:
+
+``` motoko
+let n : Nat = 0;
+let oops = if (n % 2 == 0) #even else 0;
+```
+
+## `if`-expression
+
+An `if`-expression takes the form `if  ` and is like an `if-else` but omits the else and second branch `else `.
+
+An `if`-expression is used purely for its side effects to conditionally evaluate a single branch when the condition is true, and do nothing otherwise. It returns the trivial value `()`, and its type is `()`.
+
+`if`-expressions are best suited for situations where you need to perform conditional actions, such as logging or modifying state based on certain conditions.
+
+Since `if`-expressions have type `()`, they can be used as declaration expressions.
+
+```motoko no-repl
+let x : Int = 1;
+
+if (x == 1) {
+    Debug.print("x is 1"); // Prints and returns ()
+};
+```
+
+
+## Nesting `if-else` expressions
+
+`if-else` expressions can be nested and associate to the right. This ensures the following code works as intended and the second `else` belongs to the second, nested `if`.
+
+```motoko no-repl
+var age = 21;
+
+if (age < 18) {
+  "You are a minor."
+} else if (age >= 18 and age < 65) {
+  "You are an adult."
+} else {
+  "You are a senior citizen."
+};
+```
+
+
diff --git a/docs/languages/motoko/fundamentals/contextual-dot.md b/docs/languages/motoko/fundamentals/contextual-dot.md
new file mode 100644
index 00000000..587ac851
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/contextual-dot.md
@@ -0,0 +1,165 @@
+---
+title: "Contextual dot notation"
+description: "Motoko language documentation"
+---
+
+Contextual dot notation is a language feature that allows you to call functions from modules using object-oriented style syntax, where a value appears as the receiver of a method call. This feature bridges the gap between Motoko's procedural and object-oriented programming styles.
+
+## Overview
+
+In Motoko, there are two main approaches to organizing and calling related functions: the object-oriented approach using classes and methods, and the procedural approach using modules and functions. Contextual dot notation allows you to use familiar method-like syntax for module functions, improving code readability and enabling better IDE support for code completion.
+
+### The problem with traditional functional style
+
+Consider a common operation on data structures. Without contextual dot notation, you would write:
+
+```motoko
+import Array "mo:core/Array";
+
+let numbers = [1, 2, 3, 4, 5];
+let doubled = Array.map(numbers, func(n) { n * 2 });
+```
+
+This functional style, while powerful, has some drawbacks:
+
+- Code completion and IDE support are less effective because the function name comes first
+- It reads "backwards" compared to how many developers think about operations
+- The receiver value is separated from the operation by the module name and function
+
+### Contextual dot notation syntax
+
+With contextual dot notation, you can rewrite the same code as:
+
+```motoko
+import Array "mo:core/Array";
+
+let numbers = [1, 2, 3, 4, 5];
+let doubled = numbers.map(func(n) { n * 2 });
+```
+
+This reads more naturally: "take numbers and map over them". The IDE can also provide better code completion since it knows about all available operations for that type.
+
+## How it works
+
+Contextual dot notation works by allowing a module function to be called using dot notation syntax if its first parameter is of the appropriate type. The compiler treats `value.function(args)` as syntactic sugar for `Module.function(value, args)`.
+
+### Requirements for contextual dot notation
+
+For a function to be usable with contextual dot notation, it must:
+
+1. be defined in a module (not a class method or object method),
+2. have the first parameter named `self`
+3. be publicly exported from its module.
+
+The self parameter is indicated by its position as the first parameter and its type matching the value it's called on.
+
+### Example: Using contextual dot notation
+
+Here's a more comprehensive example using the `Array` module:
+
+```motoko
+import Array "mo:core/Array";
+import Nat "mo:core/Nat";
+
+let numbers = [1, 2, 3, 4];
+
+// Traditional functional style
+let doubled1 = Array.map(numbers, func(n) { n * 2 });
+
+// Using contextual dot notation
+let doubled2 = numbers.map(func(n) { n * 2 });
+
+// Both produce the same result
+assert Array.equal(doubled1, doubled2, Nat.equal);
+```
+
+## Enabling contextual dot notation in modules
+
+When defining your own modules, you can make functions available through contextual dot notation. The first parameter of your function acts as the implicit receiver.
+
+### Defining a contextual method
+
+Here's how to define a module that supports contextual dot notation:
+
+```motoko no-repl
+module TextExt {
+  // This function can be called as "str.uppercase()" due to contextual dot notation
+  public func uppercase(self : Text) : Text {
+    // Implementation here
+  };
+
+  public func lowercase(self : Text) : Text {
+    // Implementation here
+  };
+
+  public func contains(self : Text, substring : Text) : Bool {
+    // Implementation here
+  };
+}
+```
+
+You would then use these functions as:
+
+```motoko no-repl
+import TextExt "mo:text-utils/TextExt";
+
+let message = "Hello World";
+let upper = message.uppercase();
+let lower = message.lowercase();
+let found = message.contains("World");
+```
+
+### Naming conventions
+
+While any function can use contextual dot notation based on its first parameter type, consider these guidelines:
+
+- Use verb-based names for transformation and query operations: `map`, `filter`, `find`, `contains`, `replace`
+- Use noun-based names for accessor or constructor operations: `size`, `length`, `keys`, `values`
+- Avoid overly generic names that might be ambiguous across different types
+
+## Contextual dot notation with generics
+
+Contextual dot notation works seamlessly with generic types:
+
+```motoko
+import Array "mo:core/Array";
+
+// These work with any type T
+let naturals : [Nat] = [1, 2, 3];
+let doubled = naturals.map(func(n) { n * 2 });
+
+let texts : [Text] = ["a", "b", "c"];
+let uppercased = texts.map(func(t) { /* convert to uppercase */ });
+```
+
+## Compiler warnings and best practices
+
+The Motoko compiler can optionally warn you about opportunities to use contextual dot notation. You can enable this with the `-W M0236` flag:
+
+```bash
+moc -W M0236 myfile.mo
+```
+
+This helps you maintain consistent coding style across your project.
+
+### When to use contextual dot notation
+
+- **Use it** when the syntax is clearer and more readable
+- **Use it** for commonly used operations like `map`, `filter`, `sort`, `find`
+- **Consider the context** - in complex expressions, the functional style may be clearer
+- **Avoid it** for less common or specialized operations where the module name provides important semantic information
+
+## Limitations and considerations
+
+Contextual dot notation has some intentional limitations:
+
+- It requires the receiving value to be the first parameter, named `self`.
+- Any function must be declared in a module that is imported or otherwise in scope: function in object, actors or nested modules are not considered.
+- If there is more than one available module function, and none is more general than all the others, the call is considered ambigious and rejected at compile-time.
+- The feature is purely syntactic - there is no runtime overhead
+
+
+## See also
+
+- [Modules and imports](modules-imports)
+- [Language reference](https://docs.motoko.org#dotted-function-calls)
\ No newline at end of file
diff --git a/docs/languages/motoko/fundamentals/data-persistence.md b/docs/languages/motoko/fundamentals/data-persistence.md
new file mode 100644
index 00000000..3ba0b06b
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/data-persistence.md
@@ -0,0 +1,215 @@
+---
+sidebar_position: 3
+description: "Motoko language documentation"
+title: "Data persistence"
+---
+
+One key feature of Motoko is its ability to automatically persist the program's state without explicit user instruction. This is called **orthogonal persistence**. Data persists across transactions and canister upgrades.
+
+Motoko data persistence is not simple, but it prevents data corruption or loss while being efficient at the same time. No database, stable memory API, or stable data structure is required to retain state across upgrades. Instead, a simple `stable` keyword is sufficient to declare a data structure of arbitrary shape persistent, even if the structure uses sharing, has a deep complexity, or contains cycles transfers.
+
+In comparison to other supported languages for building canisters, such as Rust, data persistence must be achieved through explicit use of stable data structures and stable memory, as other languages are not designed for orthogonal persistence and instead rearranges memory structures in an uncontrolled manner on re-compilation or at runtime.
+
+## Declaring stable variables
+
+Within an actor, you can configure which part of the program is considered to be persistent (retained across upgrades) and which part is ephemeral (reset on upgrades).
+
+More precisely, each `let` and `var` variable declaration in an actor can specify whether the variable is `stable` or `transient`. If you don’t provide a modifier, the variable is assumed to be `transient` by default.
+
+* `stable` means that all values directly or indirectly reachable from that stable variable are considered persistent and are automatically retained across upgrades. This is the primary choice for most of the program's state.
+
+* `transient` means that the variable is re-initialized on upgrade such that the values referenced by the transient variable are discarded, unless the values are transitively reachable by other variables that are stable. `transient` is only used for temporary state or references to high-order types, such as local function references.
+
+:::note
+
+You can only use the `stable`, `transient` (or legacy `flexible`) modifier on `let` and `var` declarations that are **actor fields**. You cannot use these modifiers anywhere else in your program.
+
+:::
+
+The following is a simple example of how to declare a stable counter that can be upgraded while preserving the counter’s value:
+
+```motoko
+persistent actor Counter {
+
+  var value = 0;
+
+  public func inc() : async Nat {
+    value += 1;
+    return value;
+  };
+}
+```
+
+When you compile and deploy a canister for the first time, all transient and stable variables in the actor are initialized in sequence. When a canister is upgraded, all stable variables that existed in the previous version of the actor are pre-initialized with their old values and the remaining transient and any newly-added stable variables are initialized in sequence.
+
+Starting with Motoko v0.13.5, if you prefix the `actor` keyword with the keyword `persistent`, then all `let` and `var` declarations of the actor or actor class are implicitly declared `stable`. Only `transient` variables will need an explicit `transient` declaration.
+
+Using a `persistent` actor can help avoid unintended data loss. It is the recommended declaration syntax for actors and actor classes. The non-`persistent` declaration is provided for backwards compatibility.
+
+```motoko
+persistent actor Counter {
+
+  var value = 0; // implicitly stable!
+
+  public func inc() : async Nat {
+    value += 1;
+    value;
+  };
+}
+```
+
+## Stable types
+
+The Motoko compiler must ensure that stable variables are compatible with the upgraded program. To achieve this, every `stable` variable must have a stable type. A type is stable if removing all `var` modifiers from it results in a shared type.
+
+The only difference between stable types and shared types is the former’s support for mutation. Like shared types, stable types are restricted to first-order data, excluding local functions and structures built from local functions (such as class instances). Excluding local functions is required because the meaning of a function value, consisting of both data and code, cannot easily be preserved across an upgrade while the value of plain data, mutable or not, can be.
+
+:::note
+
+In general, classes are not stable because they can contain local functions. However, a plain record of stable data is a special case of object types that are stable. Moreover, references to actors and shared functions are also stable, allowing you to preserve their values across upgrades.
+
+:::
+
+## Converting non-stable types into stable types
+
+For variables that do not have a stable type, there are two options for making them stable:
+
+1. Use a `stable` module for the type, such as:
+
+  - [StableBuffer](https://github.com/canscale/StableBuffer)
+  - [StableHashMap](https://github.com/canscale/StableHashMap)
+  - [StableRBTree](https://github.com/canscale/StableRBTree)
+
+:::note
+Unlike stable data structures in the Rust CDK, these modules do not use stable memory but instead rely on orthogonal persistence. The adjective "stable" only denotes a stable type in Motoko.
+:::
+
+2. Extract the state in a stable type and wrap it in the non-stable type.
+
+For example, the stable type `TemperatureSeries` covers the persistent data, while the non-stable type `Weather` wraps this with additional methods (local function types).
+
+``` motoko no-repl file=../../examples/WeatherActor.mo
+```
+
+__Discouraged and not recommended__: [Pre- and post-upgrade hooks](#preupgrade-and-postupgrade-system-methods) allow copying non-stable types to stable types during upgrades. This approach is error-prone and does not scale for large data. **Per best practices, using these methods should be avoided if possible.** Conceptually, it also does not align well with the idea of orthogonal persistence.
+
+## Stable type signatures
+
+The collection of stable variable declarations in an actor can be summarized in a stable signature. The textual representation of an actor’s stable signature resembles the internals of a Motoko actor type. It specifies the names, types, and mutability of the actor’s stable fields, possibly preceded by relevant Motoko type declarations.
+
+
+``` motoko no-repl
+actor {
+  stable x : Nat;
+  stable var y : Int;
+  stable z : [var Nat];
+};
+```
+
+:::tip
+
+You can emit the stable signature of an actor or actor class to a `.most` file using `moc` compiler option `--stable-types`. You should never need to author your own `.most` file.
+
+:::
+
+A stable signature `` is stable-compatible with another signature `` if, for every stable field `: T` in ``, the following condition holds:
+
+- `` has a stable field `: U` such that `T` is a stable subtype of `U`.
+
+#### Notes
+- `` may include additional fields not present in ``.
+- Matching fields may differ in mutability (`var` vs. non-`var`).
+
+`` represents the signature of an older version, and `` represents a newer version.
+
+The stable subtyping condition ensures that the final value of a field from the old version can be safely used as the initial value of that field in the new version, without loss of data.
+
+:::tip
+
+You can check the stable-compatibility of two `.most` files containing stable signatures using the `moc` compiler option `--stable-compatible file1.most file2.most`.
+
+:::
+
+
+## Upgrade safety
+
+When upgrading a canister, it is important to verify that the upgrade can proceed without:
+
+-   Introducing an incompatible change in stable declarations.
+-   Breaking clients due to a Candid interface change.
+
+With [enhanced orthogonal persistence](/languages/motoko/fundamentals/orthogonal-persistence-enhanced), Motoko rejects incompatible changes of stable declarations during an upgrade attempt.
+Moreover, `dfx` checks the two conditions before attempting the upgrade and warns users as necessary.
+
+A Motoko canister upgrade is safe provided:
+
+-  The canister’s Candid interface evolves to a Candid subtype. You can check valid Candid subtyping between two services described in `.did` files using the [`didc` tool](https://github.com/dfinity/candid) with argument `check file1.did file2.did`.
+-  The canister’s Motoko stable signature evolves to a stable-compatible one.
+
+:::danger
+With [classical orthogonal persistence](/languages/motoko/fundamentals/orthogonal-persistence-classical), the upgrade can still fail due to resource constraints. This is problematic as the canister can then not be upgraded. It is therefore strongly advised to test the scalability of upgrades extensively. This does not apply to enhanced orthogonal persistence.
+:::
+
+
+## Upgrading a canister
+
+If you have a Motoko canister that has already been deployed, then you make changes to that canister's code and want to upgrade it, the command `dfx deploy` will check that the interface is compatible, and if not, displays a warning:
+
+```
+You are making a BREAKING change. Other canisters or frontend clients relying on your canister may stop working.
+```
+
+Motoko canisters using enhanced orthogonal persistence implement an extra safeguard in the runtime system to ensure that the stable data is compatible to exclude any data corruption or misinterpretation. Moreover, `dfx` also warns about incompatibility and dropping stable variables.
+
+## Data migration
+
+Often, data representation changes with a new program version. For orthogonal persistence, it is important the language is able to allow flexible data migration to the new version.
+
+Motoko supports two kinds of data migrations: Implicit migration and explicit migration.
+
+### Implicit migration
+
+Migration is automatically supported when the new program version is stable-compatible with the old version. The runtime system of Motoko then automatically handles the migration on upgrade.
+
+More precisely, the following changes can be implicitly migrated:
+* Adding actor fields.
+* Changing the mutability of an actor field.
+* Adding variant fields.
+* Changing `Nat` to `Int`.
+* Any change that is allowed by Motoko stable subtyping rules. These are similar to Motoko subtyping, but stricter, and do not allow dropping of record fields or promotion to the type `Any`, either of which can result in data loss.
+
+Motoko versions prior to v0.14.6 allowed actor fields to be dropped or promoted to `Any`, but such changes now require explicit migrations.
+The rules have been strengthened to prevent accidental loss of data.
+
+### Explicit migration
+
+More complex migration patterns, which involve non-trivial data transformations, are possible. However, they require additional coding effort and careful handling.
+
+One common approach is to replace a set of stable variables with new ones of different types through a sequence of upgrade steps. Each step incrementally transforms the program state, ultimately producing the desired structure and values.
+
+For this purpose, a three step approach is taken:
+1. Introduce new variables of the desired types while keeping the old declarations.
+2. Write logic to copy the state from the old variables to the new variables upon upgrade.
+3. Drop the old declarations once all data has been migrated.
+
+A cleaner, more maintainable solution, is to declare an explicit migration expression that is used to transform a subset of existing stable variables into a subset of replacement stable variables.
+
+Both of these data migration paths are supported by static and dynamic checks that prevent data loss or corruption. A user may still lose data due to coding errors, so should tread carefully.
+
+For more information, see the [example of explicit migration](/languages/motoko/fundamentals/compatibility#explicit-migration-using-a-migration-function) and the
+reference material on [migration expressions](https://docs.motoko.org#migration-expressions).
+
+## Legacy features
+
+:::danger
+Using the pre- and post-upgrade system methods is discouraged. It is error-prone and can render a canister unusable. In particular, if a `preupgrade` method traps and cannot be prevented from trapping by other means, then your canister may be left in a state in which it can no longer be upgraded. Per best practices, using these methods should be avoided if possible.
+:::
+
+Motoko supports user-defined upgrade hooks that run immediately before and after an upgrade. These upgrade hooks allow triggering additional logic on upgrade.
+They are declared as `system` functions with special names, `preugrade` and `postupgrade`. Both functions must have type `: () → ()`.
+
+If `preupgrade` raises a trap, hits the instruction limit, or hits another IC computing limit, the upgrade can no longer succeed and the canister is stuck with the existing version.
+
+`postupgrade` is not needed, as the equal effect can be achieved by introducing initializing expressions in the actor, e.g. non-stable `let` expressions or expression statements.
+
+
diff --git a/docs/languages/motoko/fundamentals/defining-an-actor.md b/docs/languages/motoko/fundamentals/defining-an-actor.md
new file mode 100644
index 00000000..bbf03d2f
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/defining-an-actor.md
@@ -0,0 +1,80 @@
+---
+sidebar_position: 1
+description: "Motoko language documentation"
+title: "Defining an actor"
+hide_table_of_contents: true
+---
+
+In Motoko, an **actor** is a computational process with its own [state](/languages/motoko/fundamentals/state) and behavior. Actors are declared with the `actor` keyword.
+
+Unlike traditional functions or objects in other programming languages, actors operate independently and communicate via [asynchronous](/languages/motoko/fundamentals/actors-async#async--await) messaging. Each actor maintains its own message queue, enabling concurrent execution.
+
+An actor's state is defined by its private variables, while its behavior is defined by the public functions it exposes to other actors.
+
+You should define an actor when you want to encapsulate state and expose a public API that can be accessed asynchronously by other actors, canisters, or external clients.
+
+More specifically, define an actor when:
+
+- You are building a canister smart contract that maintains private state and exposes public functions.
+- You want to create an application that runs on the Internet Computer and is accessible by users or other canisters.
+- You want to take advantage of the actor model's benefits, such as memory isolation, single-threaded execution for update calls (avoiding race conditions), and asynchronous communication.
+
+In Motoko, actors are defined at the top level of a source file using the `actor` keyword. Public functions within an actor return their results in `async` types (otherwise known as futures) to support asynchronous calls from remote callers.
+
+An actor definition is required for a Motoko program to be deployed as a canister on ICP.
+
+Each actor maintains separate queues of incoming messages, one per sender. Messages are processed in order, ensuring that one message cannot interfere with another. This protects the actor's state from concurrent modification.
+
+Since actors process messages independently, multiple actors can handle messages in parallel, enabling concurrent execution across actors.
+
+
+```motoko name=Main
+// Declares an actor named Main.
+persistent actor Main {
+  // Define a private variable called 'count' to track the number of greetings.
+  var count : Nat = 0;
+
+  // Define a public function that asynchronously returns a greeting
+  // and increments the counter.
+  public func greet(name : Text) : async Text {
+    count += 1;
+    "Hello, " # name # "! You are visitor number " # debug_show(count);
+  };
+
+  // Define a publicly called function to
+  // return the current value of 'count' separately.
+  public query func readCount() : async Nat {
+    count
+  };
+};
+```
+
+:::note
+This code defines an actor that can be deployed on ICP.
+The actor is declared as `persistent` so that its state, `count`, will be preserved
+when the actor is upgraded.
+Learn more about [persistence](/languages/motoko/fundamentals/data-persistence).
+:::
+
+Another actor can call `Main.greet()` with an argument and await the result:
+
+```motoko no-repl
+await Main.greet("Programmer");
+```
+
+A Motoko actor always presents its interface as a suite of named [functions](/languages/motoko/fundamentals/functions) (also called methods) with defined argument and return types. When Motoko code is compiled, this interface is automatically translated to [Candid](https://internetcomputer.org/docs/building-apps/interact-with-canisters/candid/candid-concepts), an interface description language. The Candid description can be consumed by other canisters, including canisters written in another language such as Rust.
+
+The above example's corresponding Candid interface can be found below.
+
+```did
+service : {
+  greet : (text) -> (text);
+  readCount : () -> (nat) query;
+}
+```
+
+
+## Resources
+
+- [Actors](/languages/motoko/fundamentals/actors-async)
+
diff --git a/docs/languages/motoko/fundamentals/enhanced-multi-migration.md b/docs/languages/motoko/fundamentals/enhanced-multi-migration.md
new file mode 100644
index 00000000..b4b03d0c
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/enhanced-multi-migration.md
@@ -0,0 +1,417 @@
+---
+sidebar_position: 8
+description: "Motoko language documentation"
+title: "Enhanced multi-migration"
+---
+
+Enhanced multi-migration lets you manage canister state changes over time through a series of migration modules, each stored in its own file. Instead of writing a single inline migration function, one builds up a chain of small, self-contained migrations that the compiler and runtime apply in order.
+
+This approach is especially useful for long-lived canisters whose data shape evolves across many deployments. Each migration captures one logical change — adding a field, renaming a field, changing a type — and the compiler verifies that the entire chain is consistent.
+
+## Overview
+
+With enhanced multi-migration you:
+
+1. Create a `migrations/` directory alongside your actor source.
+2. Add one `.mo` file per migration, named with a timestamp prefix so they sort chronologically.
+3. Each migration module exports a `public func migration({...}) : {...}` that transforms a subset of stable fields.
+4. Pass `--enhanced-migration ./migrations` to `moc` when compiling.
+
+The compiler reads all migration modules in lexicographic order, checks that they compose correctly, and compiles them into the actor. At runtime, only migrations that have not yet been applied are executed — already-applied migrations are skipped automatically.
+
+:::note
+Enhanced multi-migration requires enhanced orthogonal persistence. It cannot be combined with the inline `(with migration = ...)` syntax used for [single migration functions](/languages/motoko/fundamentals/compatibility#explicit-migration-using-a-migration-function).
+:::
+
+## Getting started
+
+### Setting up the migration directory
+
+Create a `migrations/` directory next to your actor source. Each file in this directory is a migration module. Name files with a timestamp prefix so they sort in the intended order:
+
+```
+my-canister/
+├── src/
+│   └── main.mo
+└── migrations/
+    ├── 20250101_000000_Init.mo
+    ├── 20250315_120000_AddProfile.mo
+    └── 20250601_090000_RenameField.mo
+```
+
+### Writing a migration module
+
+Each migration module must export a `public func migration` that takes a record of input fields and returns a record of output fields:
+
+```motoko no-repl
+// migrations/20250101_000000_Init.mo
+module {
+  public func migration(_ : {}) : { name : Text; balance : Nat } {
+    { name = ""; balance = 0 }
+  }
+}
+```
+
+The input record describes which stable fields this migration reads from the current state. The output record describes which fields this migration produces. The input field types must be compatible with the state at that point in the chain, and the output field types must ultimately be compatible with the new actor's declared stable fields. A migration only needs to mention the fields it cares about — all other stable fields are carried through unchanged.
+
+### The actor
+
+With enhanced multi-migration, stable actor variables are declared **without initializers**. Unlike ordinary `let` and `var` declarations in Motoko, which always require an initializing expression (e.g. `var x : Nat = 0`), an enhanced-migration actor declares only the variable's name and type:
+
+```motoko no-repl
+// src/main.mo
+actor {
+  var name : Text;     // no `= ...` — value comes from the migration chain
+  var balance : Nat;   // likewise
+  let frozen : Bool;   // `let` bindings can also be uninitialized
+
+  public func greet() : async Text {
+    "Hello, " # name # "! Your balance is " # debug_show balance
+  };
+}
+```
+
+The initial value of each uninitialized variable is determined entirely by the migration chain. When the canister is first deployed, every migration runs in order and the final state provides the values. On subsequent upgrades, only newly added migrations execute, but the result is the same: the migration chain — not the actor source — is the single source of truth for stable variable values.
+
+The compiler rejects any stable variable that carries an initializer when `--enhanced-migration` is enabled. This prevents ambiguity about whether the value comes from the migration chain or from the inline expression.
+
+:::note
+Non-stable declarations (local variables inside functions, private helper fields, etc.) still require initializers as usual. Only stable actor fields use the uninitialized syntax.
+:::
+
+### Static actor body
+
+Because the migration chain is the sole source of stable variable values, the top-level code in the actor body must be **static** — it must evaluate without immediate side effects. Arbitrary function calls, mutable updates to non-stable state, and other effectful expressions at the top level of the actor are rejected by the compiler.
+
+The one exception is calls to functions that require `` capability, such as setting up ICP timers or configuring Candid decoding limits. These calls are permitted because they do not alter stable variable state; their effects are confined to system-level configuration.
+
+```motoko no-repl
+import Timer "mo:core/Timer";
+
+actor {
+  var count : Nat;
+
+  // Allowed: system capability call to set up a recurring timer
+  ignore Timer.setTimer(#seconds 5, func () : async () {
+    count += 1;
+  });
+
+  // Rejected: top-level effectful expression
+  // let _ = Debug.print("hello");   // ERROR — not static
+};
+```
+
+This restriction ensures that the initialization of stable state is fully determined by the composition of migration functions, with no additional top-level effects in the actor body influencing the outcome.
+
+### Compiling
+
+Pass the migration directory to the compiler:
+
+```bash
+moc --enhanced-orthogonal-persistence \
+    --default-persistent-actors \
+    --enhanced-migration ./migrations \
+    src/main.mo -o main.wasm
+```
+
+## Input and output fields
+
+Each migration's `migration` function declares which fields it reads (input) and which fields it produces (output). The relationship between input and output fields determines what happens to the state:
+
+- **Input and output** — the migration transforms this field. It reads the old value and produces a new one, potentially with a different type. The output value replaces the old one in the state.
+
+- **Output only** — the migration introduces a new field. The field is added to the state with the value and type returned by the migration.
+
+- **Input only** — the migration consumes and removes this field. The field is dropped from the state. Later migrations can no longer reference it.
+
+- **Neither input nor output** — the field is untouched by this migration and carried through to the next migration (or the final actor) as-is.
+
+For example, given the state `{a : Nat; b : Text; c : Bool}` and a migration:
+
+```motoko no-repl
+module {
+  public func migration(old : { a : Nat; b : Text }) : { a : Int; d : Float } {
+    { a = old.a; d = 1.0 }
+  }
+}
+```
+
+- `a` is in both input and output: it is transformed from `Nat` to `Int`.
+- `b` is input only: it is consumed and removed from the state.
+- `d` is output only: it is newly introduced.
+- `c` is in neither: it is carried through unchanged.
+
+The resulting state is `{a : Int; c : Bool; d : Float}`.
+
+:::note
+The state's field types must be compatible with the migration's input field types. The compiler checks this and rejects the program otherwise.
+:::
+
+## How migrations compose
+
+Migrations form a chain. The compiler verifies that each migration's input is compatible with the state produced by all preceding migrations.
+
+Consider this chain:
+
+| Migration | Input | Output | Effect |
+|-----------|-------|--------|--------|
+| `Init` | `{}` | `{name : Text; balance : Nat}` | Initializes both fields |
+| `AddProfile` | `{}` | `{profile : Text}` | Adds a new field |
+| `RenameField` | `{name : Text}` | `{displayName : Text}` | Renames `name` to `displayName` |
+
+After `Init`, the state is `{name : Text; balance : Nat}`.
+
+`AddProfile` reads nothing (`{}`) and adds `profile`, so the state becomes `{name : Text; balance : Nat; profile : Text}`.
+
+`RenameField` reads `name` from the state and produces `displayName` instead. Since `name` appears in the input but not the output, it is consumed and removed. The final state is `{displayName : Text; balance : Nat; profile : Text}`.
+
+The actor must declare fields compatible with this final state.
+
+:::tip
+Each migration only needs to declare the fields it reads and produces. You do not need to repeat fields that pass through unchanged.
+:::
+
+## Common migration patterns
+
+### Initializing state
+
+The first migration in every chain initializes the actor's fields. Its input is always empty (`{}`):
+
+```motoko no-repl
+// migrations/20250101_000000_Init.mo
+module {
+  public func migration(_ : {}) : { count : Nat; header : Text } {
+    { count = 0; header = "default" }
+  }
+}
+```
+
+### Adding a field
+
+To add a new field, write a migration with an empty (or minimal) input that produces the new field:
+
+```motoko no-repl
+// migrations/20250201_000000_AddEmail.mo
+module {
+  public func migration(_ : {}) : { email : Text } {
+    { email = "" }
+  }
+}
+```
+
+All existing fields are carried through automatically.
+
+### Changing a field's type
+
+To change the type of a field, read it at its current type and produce it at the new type:
+
+```motoko no-repl
+// migrations/20250301_000000_CountToInt.mo
+module {
+  public func migration(old : { count : Nat }) : { count : Int } {
+    { count = old.count }
+  }
+}
+```
+
+Here `count` changes from `Nat` to `Int`. The compiler accepts this because `Nat` is a subtype of `Int`.
+
+### Renaming a field
+
+To rename a field, consume the old name and produce the new name:
+
+```motoko no-repl
+// migrations/20250401_000000_RenameHeader.mo
+module {
+  public func migration(old : { header : Text }) : { title : Text } {
+    { title = old.header }
+  }
+}
+```
+
+The old field `header` is removed from the state and `title` takes its place.
+
+### Removing a field
+
+To drop a field entirely, consume it in the input without producing it in the output:
+
+```motoko no-repl
+// migrations/20250501_000000_DropEmail.mo
+module {
+  public func migration(_ : { email : Text }) : {} {
+    {}
+  }
+}
+```
+
+The corresponding actor declaration should no longer include `email`.
+
+:::caution
+Consuming a field without producing it causes data loss. The compiler issues a warning when a consumed field is not present in the final actor declaration.
+:::
+
+### Transforming data
+
+Migrations can perform arbitrary computation. For example, splitting a full name into first and last:
+
+```motoko no-repl
+// migrations/20250601_000000_SplitName.mo
+import Text "mo:base/Text";
+
+module {
+  public func migration(old : { name : Text }) : { firstName : Text; lastName : Text } {
+    let parts = Text.split(old.name, #char ' ');
+    let first = switch (parts.next()) { case (?f) f; case null "" };
+    let last = switch (parts.next()) { case (?l) l; case null "" };
+    { firstName = first; lastName = last }
+  }
+}
+```
+
+## Full lifecycle example
+
+Here is how an actor's state might evolve across several deployments:
+
+**Step 1 — Initial deployment:**
+
+```motoko no-repl
+// migrations/20250101_000000_Init.mo
+module {
+  public func migration(_ : {}) : { a : Nat } {
+    { a = 0 }
+  }
+}
+```
+
+```motoko no-repl
+actor {
+  var a : Nat;
+}
+```
+
+State: `{a : Nat}`
+
+**Step 2 — Add field `b`:**
+
+```motoko no-repl
+// migrations/20250201_000000_AddB.mo
+module {
+  public func migration(_ : {}) : { b : Int } {
+    { b = 0 }
+  }
+}
+```
+
+```motoko no-repl
+actor {
+  var a : Nat;
+  var b : Int;
+}
+```
+
+State: `{a : Nat; b : Int}`
+
+**Step 3 — Change `b` from `Int` to `Bool`:**
+
+```motoko no-repl
+// migrations/20250301_000000_ChangeBType.mo
+module {
+  public func migration(old : { b : Int }) : { b : Bool } {
+    { b = old.b > 0 }
+  }
+}
+```
+
+```motoko no-repl
+actor {
+  var a : Nat;
+  var b : Bool;
+}
+```
+
+State: `{a : Nat; b : Bool}`
+
+**Step 4 — Drop field `a`:**
+
+```motoko no-repl
+// migrations/20250401_000000_DropA.mo
+module {
+  public func migration(_ : { a : Nat }) : {} {
+    {}
+  }
+}
+```
+
+```motoko no-repl
+actor {
+  var b : Bool;
+}
+```
+
+State: `{b : Bool}`
+
+**Step 5 — Reintroduce `a` with a new type:**
+
+```motoko no-repl
+// migrations/20250501_000000_AddAText.mo
+module {
+  public func migration(_ : {}) : { a : Text } {
+    { a = "" }
+  }
+}
+```
+
+```motoko no-repl
+actor {
+  var a : Text;
+  var b : Bool;
+}
+```
+
+State: `{a : Text; b : Bool}`
+
+Note that reintroducing `a` is allowed because it was fully dropped in step 4. The new `a : Text` is independent of the old `a : Nat`.
+
+## Key properties
+
+### Idempotency
+
+Each migration is recorded after it runs. If the canister is redeployed with the same set of migrations, already-applied migrations are skipped. Redeploying is a safe no-op.
+
+### Fast-forward upgrades
+
+A canister does not need to be upgraded one version at a time. If a canister was last deployed at migration 3 and the new code includes migrations 1 through 10, the runtime applies migrations 4 through 10 in sequence. Skipping intermediate deployments is safe.
+
+### Partial migrations
+
+Each migration only mentions the fields it transforms. Unmentioned fields are carried through from the previous state unchanged. This keeps migration modules small and focused.
+
+### Init migration required
+
+The first migration in the chain must initialize all required fields. When a canister is deployed for the first time, all migrations run in order, starting from the first one.
+
+## Restrictions
+
+- Each migration file must be a module containing a `public func migration(...)`.
+- The `--enhanced-migration` flag cannot be combined with the inline `(with migration = ...)` syntax.
+- Enhanced multi-migration requires enhanced orthogonal persistence.
+- Stable actor variables must be declared without initializers (e.g. `var x : Nat`, not `var x : Nat = 0`). The compiler rejects stable variables that carry an initializing expression.
+- The actor body must be static: top-level effectful expressions and most function calls are rejected. Only calls requiring `` capability (e.g. timer setup, Candid decoding configuration) are permitted.
+- The state after each migration (its output merged with carried-through fields) must be compatible with the input of the next migration in the chain. The compiler rejects the program if this is not the case.
+- The final state must be compatible with the actor's declared stable fields.
+- Fields in the last migration's output that are not declared in the actor are rejected by the compiler.
+
+## Usage
+
+```bash
+moc --enhanced-orthogonal-persistence \
+    --default-persistent-actors \
+    --enhanced-migration ./migrations \
+    actor.mo -o actor.wasm
+```
+
+## See also
+
+- [Data persistence](/languages/motoko/fundamentals/data-persistence)
+- [Verifying upgrade compatibility](/languages/motoko/fundamentals/compatibility)
+- [Enhanced orthogonal persistence](/languages/motoko/fundamentals/orthogonal-persistence-enhanced)
diff --git a/docs/languages/motoko/fundamentals/error-handling.md b/docs/languages/motoko/fundamentals/error-handling.md
new file mode 100644
index 00000000..a769f6fd
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/error-handling.md
@@ -0,0 +1,123 @@
+---
+sidebar_position: 9
+description: "Motoko language documentation"
+title: "Error handling"
+---
+
+Using `Option` or `Result` is the preferred way of signaling errors in Motoko. They work in both synchronous and asynchronous contexts and make your APIs safer to use by encouraging clients to consider the error cases as well as the success cases. Exceptions should only be used to signal unexpected error states.
+
+In addition to explicit error handling, Motoko provides traps and assertions for dealing with execution errors.
+
+## Error reporting with `Option` types
+
+When a function might either return a value of type `A` or signal an error, it can return an option type `?A`. In this pattern, `null` is used to indicate an error or missing result, while `?value` wraps a successful outcome.
+
+In the following example, if the `markDone` function sometimes fails and returns a number of seconds on success, its return type would be `async ?Seconds`. This makes it clear to callers that the result may be absent and must be handled safely.
+
+
+Function definition:
+
+``` motoko no-repl file=../examples/todo-error.mo#L49-L58
+```
+
+Function callsite:
+
+``` motoko no-repl file=../examples/todo-error.mo#L117-L126
+```
+
+The main drawback of using option types to signal errors is that all failures are represented by a single, non-descriptive `null` value. This means important information about why something failed is lost. As a result, the only message the program can show the user might be something vague like `"Something went wrong."`
+
+For this reason, option types should only be used for errors when there's just one clear reason for failure, and it can be easily understood at the callsite.
+
+## Error reporting with `Result` types
+
+While options are a built-in type, the `Result` is defined as a variant type like so:
+
+``` motoko no-repl
+type Result = { #ok : Ok; #err : Err }
+```
+
+Unlike option types, the Result type includes a second type parameter `Err` which allows you to specify exactly what kind of error occurred. This makes error handling more informative and flexible.
+
+``` motoko no-repl file=../examples/todo-error.mo#L60-L60
+```
+
+The previous example can be revised to use `Result` types:
+
+Function definition:
+
+``` motoko no-repl file=../examples/todo-error.mo#L62-L76
+```
+
+Function callsite:
+
+``` motoko no-repl file=../examples/todo-error.mo#L128-L141
+```
+
+## Pattern matching
+
+The most common way of working with `Option` and `Result` is to use pattern matching. If you have a value of type `?Text`, you can use the `switch` keyword to access the potential [`Text`](https://mops.one/core/docs/Text) contents:
+
+``` motoko no-repl file=../examples/error-examples.mo#L3-L10
+```
+
+Motoko does not let you access the optional value without also considering the case that it is missing.
+
+With a `Result` type, you can use pattern matching to handle both success and error cases. Unlike option types, the `#err` case carries detailed information about what went wrong, not just a `null` value.
+
+``` motoko no-repl file=../examples/error-examples.mo#L12-L19
+```
+
+Sometimes you need to convert between `Option` and `Result` types. For example, a HashMap lookup returns `null` on failure (an `Option`), but if the caller has more context, they can turn that failure into a meaningful `Result` with an error message. On the other hand, sometimes you don’t need the extra detail from a `Result` and just want to convert any error (`#err`) into `null`.
+
+The [core](https://github.com/dfinity/motoko-core) package provides `fromOption` and `toOption` functions in the `Result` module that make converting between these two types easy.
+
+## Error reporting with `Error` (asynchronous errors)
+
+Another way to handle errors in Motoko is with asynchronous `Error` handling, which is a limited form of exception handling. These errors can only be thrown and caught in asynchronous contexts, like inside `shared` functions or `async` blocks. Regular (non-`shared`) functions can’t use this kind of structured error handling.
+
+This means you can `throw` an `Error` to exit a shared function early, and callers can `try` to run that code and `catch` the error if it happens. However, you can only use `throw` and `catch` inside asynchronous contexts.
+
+Asynchronous `Error`s are best reserved for unexpected failures that you don’t expect most callers to handle. If you want the caller to handle possible failures explicitly, it’s better to use `Result` in your function’s return type.
+
+Here’s how the `markDone` function might look using exceptions:
+
+Function definition:
+
+``` motoko no-repl file=../examples/todo-error.mo#L78-L92
+```
+
+Function callsite:
+
+``` motoko no-repl file=../examples/todo-error.mo#L143-L150
+```
+
+## Traps
+
+Traps immediately stop execution and roll back [state](/languages/motoko/fundamentals/state). They are used for fatal errors that cannot be recovered.
+
+```motoko no-repl
+import Runtime "mo:core/Runtime";
+
+func divide(a : Nat, b : Nat) : Nat {
+    if (b == 0) {
+        Runtime.trap("Cannot divide by zero");
+    };
+    return a / b;
+};
+```
+
+## Assertions
+
+Assertions enforce expected conditions. If the condition is false, they introduce a trap but are not errors themselves.
+
+```motoko no-repl
+func validateAge(age : Nat) : () {
+    assert(age >= 18);  // Traps if age is below 18
+};
+```
+
+## How not to handle errors
+
+Using sentinel values to report errors is generally a bad practice and strongly discouraged. For example, you might have `markDone` return `-1` to indicate failure. In that case, the caller has to remember to check for that special value every time. It’s easy to forget, which can cause errors to go unnoticed or be detected too late.
+
diff --git a/docs/languages/motoko/fundamentals/expression-declarations.md b/docs/languages/motoko/fundamentals/expression-declarations.md
new file mode 100644
index 00000000..3796e1c1
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/expression-declarations.md
@@ -0,0 +1,80 @@
+---
+sidebar_position: 6
+description: "Motoko language documentation"
+title: "Expression declarations"
+---
+
+An expression declaration is a declaration that consists of a single expression. The expression is evaluated solely for its value and side effects. Unlike other declarations, it does not declare any new names.
+
+When used as an intermediate declaration within a block, a declaration expression must have type `()`.
+If it produces a value of another type, it must be preceded by the `ignore` keyword to discard the value and ensure the expression evaluates to `()`.
+
+However, when used as the final declaration in a block, the declaration expression determines the type and value of the entire block. In this case, it may be of any valid type, not just `()`.
+For example:
+
+```motoko no-repl
+var n : Nat  = 0;
+
+func regUser(name : Text) : Text {
+  ignore bumpUsers(); // Returns Nat, but result is not needed
+  let greeting = "Welcome, " # name # "!";
+  greeting
+};
+
+func bumpUsers() : Nat {
+   n += 1;
+   n
+};
+```
+
+In Motoko, expressions of type `()` play the role of statements in other languages.
+
+## Basic usage
+
+Expression declarations are commonly used for functions or operations that produce side effects, such as printing or modifying [state](/languages/motoko/fundamentals/state).
+
+```motoko no-repl
+Debug.print("Hello, Motoko!");
+```
+
+In this example, the string `"Hello, Motoko!"` is printed, but the expression is not assigned to any variable.
+
+## Expression declarations in a sequence
+
+If an expression appears inside a sequence of declarations but is not the last declaration, it must return `()` (the unit type).
+
+```motoko no-repl
+let x = 10;
+Debug.print("Processing..."); // Expression declaration with side effects
+let y = x * 2;                // Valid, since Debug.print() returns ()
+```
+
+In this example, `Debug.print()` is used for its side effect. Because it returns `()`, it can safely appear before `let y = x * 2;` in the sequence.
+
+In comparison, below is an invalid expression declaration:
+
+```motoko no-repl
+let x = 10;
+x * 2;  // This expression produces a non-`()` value but is not named or ignored.
+let y = 5;
+```
+
+The expression `x * 2;` returns a value of type `Nat`, but since it is not assigned to a variable and is not the last declaration, this is invalid. Declaration expressions in intermediate positions must return `()` or be marked `ignore`.
+
+## Anonymous functions
+
+Motoko supports anonymous functions as a type of expression.
+
+``` motoko no-repl
+func applyFunction(f :  Int -> Int, value : Int) : Int { f(value) };
+applyFunction( func (x : Int) : Int { x * 2 } , 2);
+```
+
+In this example, the first argument to `applyFunction` is the anonymous function `func (x : Int) : Int { x * 2 }`.
+This is just an anonymous version of the function named `double` above.
+
+The compiler can infer the argument and result types of anonymous functions, when the types are determined from the context, so you can even just write:
+
+``` motoko no-repl
+applyFunction( func x { x * 2 } , 2);
+```
diff --git a/docs/languages/motoko/fundamentals/function-declarations.md b/docs/languages/motoko/fundamentals/function-declarations.md
new file mode 100644
index 00000000..e718b186
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/function-declarations.md
@@ -0,0 +1,131 @@
+---
+sidebar_position: 2
+description: "Motoko language documentation"
+title: "Function declarations"
+---
+
+A function in Motoko is a reusable block of code that accepts inputs, performs computations or actions, and optionally returns a result. Functions can be either named or anonymous and may explicitly define the types of their parameters and return values for clarity and type safety.
+
+## Declaring a function
+
+Functions are declared using the `func` keyword. A named function assigns the function to an identifier, making it accessible for reuse and enabling recursion. This allows the function to refer to itself by name within its own body. In contrast, anonymous functions (e.g., lambda functions or function expressions) do not have a name and are typically defined inline. These functions are often assigned to variables or passed directly as arguments to other functions.
+
+```motoko no-repl
+// The function is named 'add'
+// 'a : Int' and 'b : Int' are parameters with types.
+// 'Int' is the return type.
+func add(a : Int, b : Int) : Int {
+    // Exits the function and provides a result.
+    return a + b;
+}
+```
+
+In Motoko, explicit `return` expressions are only required for early returns that redirect control-flow.
+Generally, a function body will return the value of its last expression, so you can also write:
+
+```motoko no-repl
+func add(a : Int, b : Int) : Int {
+    a + b;
+}
+```
+
+## Calling a function
+
+To execute a function, you simply call it by its name (or reference, in the case of anonymous functions) and pass the required arguments in parentheses. The arguments must match the number and types specified in the function’s definition.
+
+```motoko no-repl
+func add(a : Int, b : Int) : Int {
+    return a + b;
+};
+add(3, 5);
+```
+
+## Functions as values
+
+Functions in Motoko are first-class values, meaning they can be treated like any other value in the language. They can be assigned to variables, stored in data structures such as arrays or records, and passed as arguments to other functions.
+
+```motoko no-repl
+func double(x : Int) : Int { x * 2 };
+func applyFunction(f : Int -> Int, value : Int) : Int { f(value) };
+
+applyFunction(double, 10);
+```
+
+`applyFunction` takes a function `f` and applies it to `value`. Because `applyFunction` takes a function as a parameter, it it is a _higher-order_ function.
+
+In the call, the function `double` is passed as an argument.
+
+## Recursive functions
+
+A function that calls itself is a recursive function. Recursion enables looping behavior by having a function repeatedly invoke itself, typically with smaller arguments, until a base case is reached. 
+
+```motoko no-repl
+func factorial(n : Nat) : Nat {
+    if (n == 0) {
+        return 1;
+    };
+     // Calls itself with factorial(n - 1), reducing n until reaching 0.
+    n * factorial(n - 1);
+}
+```
+::: warning
+
+In a recursive function, each recursive call consumes stack space by allocating a new stack frame, which uses memory on the program's relatively small call stack. As a result, excessive or uncontrolled recursion can lead to stack overflow or out-of-memory errors.
+
+:::
+
+## Generic functions
+
+Generic functions are used to write reusable logic that works with any type.
+
+For example, the following function applies a given function twice to a value:
+
+```motoko no-repl
+func twice(f : T -> T) : T -> T = func (x : T) {
+  f(f(x))
+};
+```
+
+You can use it with different types:
+
+```motoko no-repl
+let cube= twice(func x { x * 2 });
+assert cube(2) == 8;
+
+let echoTwice = twice(func s { s # "!" });
+assert echoTwice("Hello") == "Hello!!";
+```
+
+## Shared functions in actors
+
+In actors, functions can be marked as `shared` to allow [asynchronous](/languages/motoko/fundamentals/actors-async#async--await) [inter-canister](https://internetcomputer.org/docs/references/async-code) communication.
+
+```motoko no-repl
+actor Counter {
+    stable var count : Nat = 0;
+
+    public func inc() : async () {
+        count += 1;
+    };
+
+    public shared query func getCount() : async Nat {
+        count;
+    }
+};
+await Counter.inc();
+await Counter.getCount();
+```
+
+### Accessing the caller identity
+
+One key advantage of shared functions in Motoko is that they have access to the caller's Principal, which uniquely identifies the entity (user or another canister) that made the request. This capability allows actors to implement access control by verifying the caller’s identity before performing sensitive operations.
+
+```motoko
+actor Example {
+    // msg.caller retrieves the Principal of the caller.
+    public shared(msg) func whoAmI() : async Principal {
+        msg.caller;
+    }
+}
+```
+
diff --git a/docs/languages/motoko/fundamentals/functions.md b/docs/languages/motoko/fundamentals/functions.md
new file mode 100644
index 00000000..24fd9825
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/functions.md
@@ -0,0 +1,327 @@
+---
+sidebar_position: 3
+description: "Motoko language documentation"
+title: "Function types"
+---
+
+Functions are reusable chunks of code that perform a specific task. A function is defined with a name and optional parameters, then returns a defined result. A function can also specify a return type for the value it produces.
+
+In the process of producing a result, the execution of the function can have other side effects, like modifying state, printing to the log, or sending messages to other canisters.
+
+Functions can be synchronous or asynchronous. A synchronous function blocks the caller until it returns with a result, just like functions in most traditional programming languages.
+
+An asynchronous function returns immediately, providing a **future** value as a placeholder for its result. The caller can await the future later to retrieve the result or ignore it and continue with other tasks.
+
+Motoko offers different types of functions, each with distinct capabilities:
+
+- **Local functions**, declared using the `func` keyword, are typically synchronous but can be asynchronous if their body contains an `async` expression. A local function is only available within the actor that defines it; it cannot be called from another actor or sent to another actor in a message.
+
+- **Shared functions**, declared using the `shared`, `shared query`, or `shared composite query` keywords, are asynchronous by nature. Calling a shared function sends a message to another actor. The caller is typically another Motoko actor, a [canister](https://internetcomputer.org/docs/building-apps/essentials/canisters), or an [agent](https://internetcomputer.org/docs/building-apps/interact-with-canisters/agents/overview).
+
+An actor's shared functions are always called as the result of the actor receiving some message. Shared functions that return a result have `async` return types.
+
+Since actors can only have `shared` functions as public members, the `shared` keyword  is optional and can be omitted from public actor functions.
+
+Motoko provides different types of functions based on where in the program they execute and how they interact with the system. Understanding these distinctions is essential when designing efficient and scalable canister logic.
+
+## Function keywords
+
+| Keyword  | Function  |
+|-------------|--------------|
+| `shared`    | Used to enable async communication between actors. Exposes the caller’s identity. |
+| `async`     | Runs the function [asynchronously](/languages/motoko/fundamentals/actors-async#async--await) and returns its result in a future. |
+| `query`     | Optimized for reading data but cannot modify [state](/languages/motoko/fundamentals/state). |
+
+## Function comparison
+
+| Function type                | Mutates [state](/languages/motoko/fundamentals/state) | Calls updates | Calls queries | Asynchronous | External calls |
+|------------------------------|---------------|------------------|------------------|---------------|---------------|
+| Local   (synchronous)                 |  Yes            | No              | No             | No    | No            |
+| Local   (asynchronous)                | Yes            | Yes              | Yes              | Yes   |  No            |
+| Shared (update)         | Yes           | Yes              | Yes              | Yes           | Yes           |
+| Shared query              | No            | No               | No              | Yes           | Yes           |
+| Shared composite query   | No            | No               | Yes              | Yes           | Yes           |
+
+## Local functions
+
+Local functions run within the canister's [actor](/languages/motoko/fundamentals/actors-async). They cannot call other [canisters](https://internetcomputer.org/docs/building-apps/essentials/canisters). Local functions are cheap to call and execute synchronously.
+
+```motoko
+persistent actor CommonDivisor{
+  func gcd(a : Nat, b : Nat) : Nat {
+    var x = a;
+    var y = b;
+
+    while (y != 0) {
+      let temp = y;
+      y := x % y;
+      x := temp;
+    };
+
+    x  // Return value is the GCD
+  };
+let greatestCommonDivisor : Nat = gcd(108, 54); // Synchronous execution
+};
+```
+
+The type of `gcd` is `(Nat, Nat) -> Nat` indicating that it expects a pair of naturals as the input argument and returns a natural as a result.
+
+**Example use case:** Local computations that do not require communication with other actors or canisters.
+
+## Generic functions
+
+Generic functions allow the use of type parameters, making them more flexible for using different data types.
+
+```motoko name=swap
+func swap(t : T, u : U) : (U, T) {
+  (u, t)
+};
+
+swap(42, "ICP"); // ("ICP", 42)
+```
+
+The type of `swap` is ` (T, U) -> (U, T)`, indicating it can accept any two types `T` and `U`, a value of tuple type `(T, U)` and return a tuple of type `(U, T)`, with the elements swapped.
+
+Type arguments can be omitted from calls when the compiler can infer them from the arguments and context, allowing the simpler code:
+
+```motoko no-repl
+let result = swap(2021, "Motoko"); // Inferred as 
+```
+
+## Local asynchronous functions
+
+Local function that have an `async` or `async*` return type are asynchronous and can interact with other canisters by calling shared functions.
+
+They are useful for defining asynchronous logic used in the implementation of public `shared` functions.
+
+```motoko no-repl
+import Time "mo:core/Time";
+import Logger "canister:Logger";
+
+persistent actor {
+  private func log(msg : Text) : async () {
+    Logger.log(Time.now() + msg); // sends a message
+  };
+  public shared func doStuff() : async () {
+    await log("doingStuff");
+  }
+}
+```
+
+A more efficient variation is to use `async*` and `await*` , which avoids the overhead of using ordinary `await` just to call a local function:
+
+```motoko no-repl
+import Time "mo:core/Time"
+import Logger "canister:Logger";
+
+persistent actor {
+  private func log(msg : Text) : async* () {
+    await Logger.log(Time.now() + msg); // sends a message
+  };
+
+  public shared func doStuff() : async () {
+    await* log("doingStuff");
+  }
+}
+```
+
+## Shared functions
+
+The public functions of an actor determine its external interface. All public functions in an actor must be shared and can be either `shared`, `shared query` or `shared composite query` functions. Private functions cannot be `shared`.
+Since an actor's public functions must be shared, the `shared` keyword is optional and can be omitted.
+
+`shared` functions permanently update the state of an actor, while `query` and `composite` `query` functions are only executed for their result.
+
+Although queries can temporarily alter the state of an actor, these changes are not permanent and are never visible to other callers. It's as if each query operates on a copy of the actor, which is discarded when the query returns.
+
+When called from a front-end, `query` functions generally have much lower latency than equivalent shared functions. This is because shared functions require the protocol to reach consensus on the state changes and results, whereas query functions do not.
+
+```motoko no-repl
+persistent actor Account {
+  var balance = 0;
+
+  public shared func deposit(amount : Nat) : async Nat {
+    balance += amount;
+    balance
+  }
+}
+```
+
+Omitting the shared keyword, we can also write:
+
+```motoko no-repl
+persistent actor Account {
+  var balance = 0;
+
+  public func deposit(amount : Nat) : async Nat {
+    balance += amount;
+    balance
+  }
+}
+```
+
+The deposit function has type `: shared Nat -> async Nat`.
+Consider this code:
+
+``` motoko
+let b1 = await Account.deposit(50);
+let b2 = await Account.deposit(50);
+(b1,b2)
+```
+The first class to `Account.balance(50)` increments `balance` from `0` to `50`, returning `50`.
+The second call increments the balance from `50` to `100`, returning `100`.
+
+Since `Account.deposit` is asynchronous, its results are returned in futures of type `async Nat`. Calling `await` on each future extracts the results of the calls when they become available (so `b1` is `50` and `b2` is `100`).
+
+**Example use case**: Transactions, user [state](/languages/motoko/fundamentals/state) updates, or anything that modifies persistent data.
+
+### One-way functions
+
+An update function can, but need not, return a future. An update function can just return `()` to indicate that it can be called for its side effect, but its result cannot be awaited.
+Such a function is called a _one-way_ (or _fire-and-forget_) function.
+
+An example of this might be a variant of `Account.deposit`, `Account.credit`, that merely updates the balance without returning its new value:
+
+```motoko no-repl
+persistent actor Account {
+  var balance = 0;
+  public func credit(amount : Nat) : () {
+    balance += amount;
+  }
+}
+```
+
+Calling `Account.credit(100)` updates the balance by `100`;
+
+``` motoko
+Account.credit(100);
+```
+
+Again, the shared keyword is optional. Note that `Account.credit(100` just returns control; it doesn't return a future that you can await. The call is executed asynchronously.
+
+
+**Example use case**: Log messages, asynchronous notifications, and messages that don't require explicit acknowledgements or return values.
+
+## Query functions
+
+[Query](https://internetcomputer.org/docs/building-apps/interact-with-canisters/query-calls) functions are designed for retrieving data. They cannot permanently update [state](/languages/motoko/fundamentals/state) and execute faster than [update](https://internetcomputer.org/docs/building-apps/interact-with-canisters/update-calls) functions because they do not go through consensus. Query functions are identified with the `query` keyword. Any function without the `query` keyword is an [update](https://internetcomputer.org/docs/building-apps/interact-with-canisters/update-calls) function.
+
+```motoko no-repl
+  public query func greet(name : Text) : async Text {
+    return greeting # name # "!";
+  };
+```
+
+
+```motoko no-repl
+persistent actor Account {
+  var balance  = 0;
+  public shared query func getBalance() : async Nat {
+     balance
+  };
+}
+```
+
+Again, you can omit the shared keyword:
+
+```motoko no-repl
+persistent actor Account {
+  var balance = 0;
+
+  public query func getBalance() : async Nat {
+    balance
+  };
+}
+```
+
+The `getBalance` function has function type `shared query () -> async Nat`.
+
+**Example use case:** Fetching data quickly without modifying the canister [state](/languages/motoko/fundamentals/state).
+
+### Composite queries
+
+[Composite queries](https://internetcomputer.org/docs/building-apps/interact-with-canisters/query-calls#composite-queries) chain multiple query calls together within the same function.
+
+A good example of a composite query might be a bank that holds references to its individual accounts, implemented as separate actors, and provides a composite query that sums the deposits in all its accounts:
+
+```motoko no-repl
+persistent actor Bank {
+  type Account =
+    actor { getBalance() : query () -> async Nat };
+
+  var accounts : [Account] = []
+
+  public shared composite query func getDeposits() : async Nat {
+    var deposits = 0;
+    for (account in accounts.values()) {
+      deposits += await account.getBalance();
+    };
+  deposits;
+  };
+}
+```
+
+Again, the shared keyword is redundant and can be omitted:
+
+```motoko no-repl
+persistent actor Bank {
+    // ... code omitted ...
+    public composite query func getDeposits() : async Nat {
+    var deposits = 0;
+    for (account in accounts.values()) {
+       deposits += await account.getBalance()
+    };
+    deposits;
+  };
+};
+```
+
+The type of `getDeposits` is `shared composite query () -> Nat`.
+
+## Passing arguments to functions
+
+An argument is a value passed to a function when called. Arguments enable functions to process incoming data during execution.
+
+### Single argument
+
+A function can take a single argument of a specific type.
+
+```motoko no-repl
+  public func increment(amount : Nat) : async Nat {
+    count += amount;
+    count;
+  }
+```
+
+### Multiple arguments and returns
+
+Functions can accept multiple arguments and return multiple results by enclosing them in parentheses separated by commas.
+
+```motoko no-repl
+  func divRem(x : Nat, y : Nat) : (Nat, Nat) {
+    (x / y, x % y)
+  }
+```
+
+### Using a record as an argument
+
+Multiple values can be passed as a single argument by encapsulating them within a [record](/languages/motoko/fundamentals/records) type.
+
+```motoko no-repl
+  func userName(user: { name : Text; age : Nat }) : Text {
+    user.name
+  }
+```
+
+### Using an array as an argument
+
+A collection of values can be passed as a single array argument.
+
+```motoko no-repl
+  public func sum(numbers : [Nat]) : async Nat {
+    var total : Nat = 0;
+    for (num in numbers.vals()) { total += num };
+    total;
+  }
+```
+
diff --git a/docs/languages/motoko/fundamentals/hello-world.md b/docs/languages/motoko/fundamentals/hello-world.md
new file mode 100644
index 00000000..4023021c
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/hello-world.md
@@ -0,0 +1,40 @@
+---
+sidebar_position: 1
+description: "Motoko language documentation"
+title: "Hello, world!"
+hide_table_of_contents: true
+---
+
+"Hello, world!" is a common starting point used to showcase a programming language's basic syntax.
+
+Below is an example of "Hello, world!" written in Motoko:
+
+```motoko
+// If an actor is declared with the persistent keyword, all private declarations are considered stable by default
+persistent actor HelloWorld {
+  // We store the greeting in a stable variable such that it gets persisted over canister upgrades.
+  var greeting : Text = "Hello, ";
+
+  // This update method modifies the greeting prefix.
+  public func setGreeting(prefix : Text) : async () {
+    greeting := prefix;
+  };
+
+  // This query method returns the currently persisted greeting with the given name.
+  public query func greet(name : Text) : async Text {
+    return greeting # name # "!";
+  };
+};
+```
+
+In this example:
+
+1. The code begins by defining an [actor](/languages/motoko/fundamentals/actors-async) named `HelloWorld`. In Motoko, an actor is an object capable of maintaining state and communicating with other entities via message passing.
+
+2. It then declares the variable `greeting`. This is a [stable variable](/languages/motoko/fundamentals/stable-types) because the actor is declared with the keyword `persistent`. Stable variables are used to store data that persists across canister upgrades. [Read more about canister upgrades.](https://internetcomputer.org/docs/building-apps/canister-management/upgrade)
+
+3. An [update method](https://internetcomputer.org/docs/building-apps/interact-with-canisters/update-calls) named `setGreeting` is used to modify the canister’s state. This method specifically updates the value stored in `greeting`.
+
+4. Finally, a [query method](https://internetcomputer.org/docs/building-apps/interact-with-canisters/query-calls) named `greet` is defined. Query methods are read-only and return information from the canister without changing its state. This method returns the current `greeting` value, followed by the input text. The method body produces a response by concatenating `"Hello, "` with the input `name`, followed by an exclamation point.
+
+[Learn more about actors and basic syntax](/languages/motoko/fundamentals/defining-an-actor).
\ No newline at end of file
diff --git a/docs/languages/motoko/fundamentals/identifiers.md b/docs/languages/motoko/fundamentals/identifiers.md
new file mode 100644
index 00000000..d629a5ba
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/identifiers.md
@@ -0,0 +1,19 @@
+---
+sidebar_position: 7
+description: "Motoko language documentation"
+title: "Identifiers"
+hide_table_of_contents: true
+---
+
+Identifiers are names used for variables, functions, types, and other entities. They must start with a letter or an underscore and can contain letters, digits, and underscores.
+
+```motoko no-repl
+let name = "Motoko";
+let a1 = 123;
+let camelCaseIdentifier = "best practice";
+let snake_case_identifier = "for compatibility with other languages";
+```
+
+## Reserved syntax keywords
+
+Motoko reserves [keywords](https://docs.motoko.org#keywords) for its syntax and they cannot be used as identifiers.
diff --git a/docs/languages/motoko/fundamentals/immutable-arrays.md b/docs/languages/motoko/fundamentals/immutable-arrays.md
new file mode 100644
index 00000000..87eab412
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/immutable-arrays.md
@@ -0,0 +1,221 @@
+---
+sidebar_position: 8
+description: "Motoko language documentation"
+title: "Immutable arrays"
+---
+
+Immutable arrays are fixed-size, read-only data structures that allow efficiently storing elements of the same type. Unlike [mutable arrays](/languages/motoko/fundamentals/mutable-arrays), they cannot be modified after creation, ensuring data integrity and predictable behavior.
+
+## When to use immutable arrays
+
+- Fixed-size storage suffices: The number of elements is known in advance and will not change.
+- Performance is required: Arrays provide efficient random access to elements.
+- Mutability is not needed: Immutability ensures that no accidental modifications occur.
+
+Unlike mutable arrays, immutable arrays support subtyping and are shared types that can be sent in messages (provided the element type is shared).
+
+If the number of elements may change, collections like `List` is a better choice, as immutable arrays require creating a new array each time an element is added or removed, which is inefficient.
+
+## Defining an immutable array
+
+Immutable arrays are declared using square brackets `[T]`. The type of the array is specified within the square brackets, e.g., `[Nat]` declares an immutable array of natural numbers.
+
+```motoko
+let arr : [Nat] = [1, 2, 3, 4, 5];
+```
+
+## Accessing and modifying elements
+
+The size of an array `a` is available as `a.size()`, a `Nat`.
+
+Array elements are zero-indexed, allowing indices `0` up to `a.size() - 1`.
+
+Attempting to access an array's index that does not exist will cause a [trap](/languages/motoko/fundamentals/traps). Attempting to modify an immutable array will result in an error `expected mutable assignment target(M0073)`.
+
+```motoko
+import Debug "mo:core/Debug";
+
+let numbers : [Nat] = [10, 20, 30];
+
+let first : Nat = numbers[0];  // 10
+let second : Nat = numbers[1]; // 20
+
+Debug.print(debug_show(first));
+Debug.print(debug_show(second));
+```
+
+## Iterating through an array
+
+There are two primary ways to iterate through the elements in an array in Motoko:
+
+1. Using `array.values()`, which provides an iterator.
+
+2. Using a `for` loop that runs from `0` to `array.size() - 1`, as arrays are zero-based.
+
+Both methods achieve the same result, but `array.values()` is often preferred for its readability and simplicity.
+
+### Using `array.values()` and `array.keys()`
+
+The `array.values()` function returns an iterator that is used to iterate over the array's elements without manually managing indices.
+
+The `array.keys()` function returns an iterator that is used to iterate over the array's valid indices (in increasing order).
+
+### Using a `for` loop
+
+A `for` loop can also be used to iterate over an array by accessing elements via their index.
+
+```motoko
+import Debug "mo:core/Debug";
+
+let arr : [Nat] = [1, 2, 3, 4, 5];
+
+for (i in arr.keys()) {
+  Debug.print(debug_show(arr[i]));
+}
+```
+
+## Converting an immutable array to a mutable array
+
+You can convert an immutable array into a mutable array using `Array.thaw` which is useful when working with data that needs to be modified in place after initially being immutable.
+
+```motoko no-repl
+let immutableArray : [Nat] = [1, 2, 3, 4, 5];
+
+let mutableCopy : [var Nat] = Array.thaw(immutableArray);
+mutableCopy[0] := 10;
+```
+
+## Passing a variable number of arguments
+
+Motoko supports passing collections to a function, ensuring that all arguments are handled as a collection rather than individual parameters.
+
+```motoko
+import Debug "mo:core/Debug"
+
+func printAllStrings(strings : [Text]) {
+  for (s in strings.values()) {
+    Debug.print(s);
+  }
+};
+
+printAllStrings(["Hello", "Hola", "Ciao"]);
+```
+
+## Comparing arrays
+
+Arrays of  shared types can be compare directly using `==`. Two arrays are considered equal if they have the same length and their corresponding elements are equal:
+
+```motoko no-repl
+let arr1 : [Nat] = [1, 2, 3];
+let arr2 : [Nat] = [1, 2, 3];
+let arr3 : [Nat] = [3, 2, 1];
+
+assert arr1 == arr2;
+assert (not (arr1 == arr3));
+```
+
+More generally, including for arrays of non-shared types, the `Array.equal(a1, a2, eq)` function can be used to check whether two arrays are equal. It takes an additional function `eq` for comparing the elements.
+
+```motoko no-repl
+import Array "mo:core/Array";
+import Nat "mo:core/Nat";
+
+let arr1 : [Nat] = [1, 2, 3];
+let arr2 : [Nat] = [1, 2, 3];
+let arr3 : [Nat] = [3, 2, 1];
+
+assert Array.equal(arr1, arr2, Nat.equal);
+assert not Array.equal(arr1, arr3, Nat.equal);
+```
+
+Unlike some languages, Motoko does not compare arrays by reference; instead, it uses proper element-by-element structural comparison.
+
+## Transforming arrays
+
+The [`Array`](https://mops.one/core/docs/Array) module in Motoko's core package contains built-in functions for mapping over elements, filtering values, and summing numerical arrays.
+
+```motoko
+import Array "mo:core/Array";
+
+func transformArray() : [Nat] {
+  let numbers : [Nat] = [1, 2, 3];
+  Array.map(numbers, func(x) { x * 2 });
+};
+transformArray();
+```
+
+## Nested immutable arrays example: Chessboard
+
+To demonstrate nested immutable arrays, consider the following:
+
+A chessboard is a fixed `8×8` grid. Using immutable arrays to represent the initial [state](/languages/motoko/fundamentals/state) of the board ensures that the setup remains unchanged, preventing accidental modifications. This is useful because the starting position of pieces in chess is fixed, and any changes should be intentional, such as when making a move. Immutable arrays provide stability and help maintain the integrity of the initial board [state](/languages/motoko/fundamentals/state).
+
+```motoko no-repl
+import Array "mo:core/Array";
+import Debug "mo:core/Debug";
+
+persistent actor Chess{
+
+  func generateChessboard() : [[Text]] {
+    let size : Nat = 8;
+
+    let board : [[Text]] = Array.tabulate<[Text]>(size, func(r : Nat) : [Text] {
+      Array.tabulate(size, func(c : Nat) : Text {
+          switch (r, c) {
+            case (0, 0) {"♜"}; case (0, 1) {"♞"}; case (0, 2) {"♝"}; case (0, 3) {"♛"}; case (0, 4) { "♚"};
+            case (0, 5) {"♝"}; case (0, 6) {"♞"}; case (0, 7) {"♜"}; case (1, _) {"♟"}; // Pawns on row 1
+            case (6, _) {"♙"}; // Pawns on row 6
+            case (7, 0) {"♖"}; case (7, 1) {"♘"}; case (7, 2) {"♗"}; case (7, 3) {"♕"};
+            case (7, 4) {"♔"}; case (7, 5) {"♗"}; case (7, 6) {"♘"}; case (7, 7) { "♖"}; case (_, _) {"."} // Empty squares
+            }
+          }
+        )
+      }
+    );
+    board
+  };
+
+  // Generate the immutable chessboard
+  let chessboard : [[Text]] = generateChessboard();
+
+  // Display the board
+  for (row in chessboard.values()) {
+    let rowText = Array.foldLeft(row, "", func(acc, square) = acc # square # " ");
+    Debug.print(rowText)
+  }
+};
+```
+
+The function `Array.tabulate(size, f)` creates an array of `size` elements, populated so that element `i` contains the value of `f(i)`.
+
+The function `Array.foldLeft` combines the squares in the row into a single text string, which can then be printed.
+
+:::note
+`Array.foldRight` is also available.
+:::
+
+``` md
+♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜
+♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟
+. . . . . . . .
+. . . . . . . .
+. . . . . . . .
+. . . . . . . .
+♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙
+♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖
+```
+
+## Subtyping
+
+Immutable arrays also support subtyping.
+
+For example, this means that, since `Nat` is a subtype of `Int`, the array type `[Nat]` is also a subtype of the array type `[Int]`.
+Similarly, `[WeekDay]` <: `[Day]`, `[ {x : Nat; y: Nat; z : Nat } ] <: [ {x : Nat, y: Nat} ]` and so on.
+
+For safety reasons, mutable arrays do not support subtyping. This is because the entries of a mutable array can also be written, not just read.
+
+## Resources
+
+- [`Array`](https://mops.one/core/docs/Array)
+- [`Iter`](https://mops.one/core/docs/Iter)
+
diff --git a/docs/languages/motoko/fundamentals/implicit-parameters.md b/docs/languages/motoko/fundamentals/implicit-parameters.md
new file mode 100644
index 00000000..0e413c4f
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/implicit-parameters.md
@@ -0,0 +1,285 @@
+---
+title: "Implicit parameters"
+description: "Motoko language documentation"
+---
+
+## Overview
+
+Implicit parameters allow you to omit frequently-used function arguments at call sites when the compiler can infer them from context. This feature is particularly useful when working with ordered collections like `Map` and `Set` from the `core` library, which require comparison functions but where the comparison logic is usually obvious from the key type.
+Other exampes are `equal` and `toText` functions.
+
+## Basic usage
+
+### Declaring implicit parameters
+
+When declaring a function, any function parameter can be declared implicit using the `implicit` type constructor:
+
+For example, the core Map library, declares a function:
+
+```motoko no-repl
+public func add(self: Map, compare : (implicit : (K, K) -> Order), key : K, value : V) {
+  // ...
+}
+```
+
+The `implicit` marker on the type of parameter `compare` indicates the call-site can omit it the `compare` argument, provided it can be inferred the call site.
+
+A function can declare more than on implicit parameter, even of the same name.
+
+
+```motoko
+func show(
+    self: (T, U),
+    toTextT : (implicit : (toText : T -> Text)),
+    toTextU : (implicit : (toText : U -> Text))) : Text {
+  "(" # toTextT(self.0) # "," # toTextU(self.1) # ")"
+}
+```
+
+In these cases, you can add an inner name to indicate the external names of the implicit parameters (both `toText`) and distinguish
+them from the names used with the function body, `toTextT` and `toTextU`: these need to be distinct so that the body can call them.
+The inner name (under `implicit`) overrides the local name of the parameter in the body.
+
+### Calling functions with implicit arguments
+
+When calling a function with implicit parameters, you can omit the implicit arguments if the compiler can infer them:
+
+```motoko
+import Map "mo:core/Map";
+import Nat "mo:core/Nat";
+
+let map = Map.empty();
+
+// Without implicits - must provide compare function explicitly
+Map.add(map, Nat.compare, 5, "five");
+
+// With implicits - compare function inferred from key type
+Map.add(map, 5, "five");
+```
+The compiler automatically finds an appropriate comparison function based on the type of the key argument.
+
+The availabe candidates are:
+* Any value named `compare` whose type matches the parameter type.
+
+If there is no such value,
+* Any field named `M.compare` declared in some module available `M`.
+* If there is more than one such field, none of which is more specific than all the others, the call is ambiguous.
+
+An ambiguous call can always be disambiguated by supplying the explicit arguments for all implicit parameters.
+
+### Contextual dot notation
+
+Implicit parameters dovetail nicely with the [contextual dot notation](contextual-dot).
+The dot notation and implicit arguments can be used in conjunction to shorten code.
+
+For example, since the first parameter of `Map.add` is called `self`, we can both use `map` as the receiver of `add` "method" calls
+and omit the tedious `compare` argument:
+
+```motoko
+import Map "mo:core/Map";
+import Nat "mo:core/Nat";
+
+let map = Map.empty();
+
+// Using contextual dot notation, without implicits - must provide compare function explicitly
+map.add(Nat.compare, 5, "five");
+
+// Using contextual dot nation together with implicits - compare function inferred from key type
+map.add(5, "five");
+```
+
+
+## Working with ordered collections
+
+The primary use case for implicit arguments is simplifying code that uses maps and sets from the `core` library.
+
+### Map Example
+
+```motoko
+import Map "mo:core/Map";
+import Nat "mo:core/Nat";
+
+let inventory = Map.empty();
+
+// Old style: explicitly pass Nat.compare
+Map.add(inventory, Nat.compare, 101, "Widget");
+Map.add(inventory, Nat.compare, 102, "Gadget");
+Map.add(inventory, Nat.compare, 103, "Doohickey");
+
+let item1 = Map.get(inventory, Nat.compare, 102);
+
+// With contextual dots and implicits: compare function inferred
+inventory.add(101, "Widget");
+inventory.add(102, "Gadget");
+inventory.add(103, "Doohickey");
+
+let item2 = inventory.get(102);
+```
+
+
+### Set example
+
+The core `Set` type also takes advantage of implicit `compare` parameters.
+```motoko
+import Set "mo:core/Set";
+import Text "mo:core/Text";
+
+let tags = Set.empty();
+
+// Old style
+Set.add(tags, Text.compare, "urgent");
+Set.add(tags, Text.compare, "reviewed");
+let hasTag1 = Set.contains(tags, Text.compare, "urgent");
+
+// With implicits
+tags.add("urgent");
+tags.add("reviewed");
+let hasTag2 = tags.contains("urgent");
+```
+
+### Building collections incrementally
+
+Implicit arguments make imperative collection operations much cleaner:
+
+```motoko
+import Map "mo:core/Map";
+import Text "mo:core/Text";
+
+let scores = Map.empty();
+
+// Add player scores
+scores.add("Alice", 100);
+scores.add("Bob", 85);
+scores.add( "Charlie", 92);
+
+// Update a score
+scores.add("Bob", 95);
+
+// Check and remove
+if (scores.containsKey("Alice")) {
+  scores.remove("Alice");
+};
+
+// Get size
+let playerCount = scores.size()
+```
+
+## How inference works
+
+The compiler infers an implicit argument by:
+
+1. Examining the types of the explicit arguments provided.
+2. Looking for all candidate values for the implicit argument in the current scope that match the required type and name.
+3. From these, selecting the best unique candidate based on type specifity.
+
+If there is no unique best candidate the compiler rejects the call as ambiguous.
+
+If a callee takes several implicits parameter, either all implicit arguments must be omitted, or all explicit and implicit arguments must be provided at the call site,
+in their declared order.
+
+### Supported types
+
+The core library provides comparison functions for common types:
+
+- `Nat.compare` for `Nat`
+- `Int.compare` for `Int`
+- `Text.compare` for `Text`
+- `Char.compare` for `Char`
+- `Bool.compare` for `Bool`
+- `Principal.compare` for `Principal`
+- etc.
+
+Other implicit parameters declared by the core library are `equals : (implicit : (T, T) -> Bool)` and `toText: (implicit : T -> Text)`.
+
+## Explicitly providing implicit arguments
+
+You can always provide implicit arguments explicitly when needed:
+
+```motoko
+import Map "mo:core/Map";
+import Nat "mo:core/Nat";
+import {type Order} "mo:core/Order";
+
+// Custom comparison function for reverse ordering
+func reverseCompare(a : Nat, b : Nat) : Order {
+  Nat.compare(b, a)
+};
+
+let reversedMap = Map.empty();
+// Explicitly provide the comparison function
+reversedMap.add(reverseCompare, 5, "five");
+reversedMap.add(reverseCompare, 3, "three");
+```
+
+This is useful when:
+- Using custom comparison logic
+- Working with custom types that have multiple possible orderings
+- Improving code clarity in complex scenarios
+
+## Custom types
+
+To use implicit arguments with your own custom types, define a comparison function:
+
+```motoko
+import Map "mo:core/Map";
+import Text "mo:core/Text";
+import {type Order} "mo:core/Order";
+
+type Person = {
+  name : Text;
+  age : Nat;
+};
+
+module Person {
+  public func compare(a : Person, b : Person) : Order {
+    Text.compare(a.name, b.name)
+  };
+};
+
+// Now works with implicits
+let directory = Map.empty();
+directory.add({ name = "Alice"; age = 30 }, "alice@example.com");
+directory.add({ name = "Bob"; age = 25 }, "bob@example.com");
+
+let email = directory.get({ name = "Alice"; age = 30 });
+```
+
+## Best practices
+
+1. **Use implicits for standard types**: When working with `Nat`, `Text`, `Int`, `Principal`, and other primitive types, let the compiler infer the comparison function.
+
+2. **Be explicit with custom logic**: When using non-standard comparison logic, explicitly provide the comparison function for clarity.
+
+3. **Name comparison functions consistently**: Follow the convention of `ModuleName.compare` to ensure proper inference.
+
+4. **Consider readability**: While implicits reduce boilerplate, explicit arguments may be clearer in some contexts, especially when teaching or documenting code.
+
+5. **Collections benefit most**: The repeated operations on `Map` and `Set` from `core` particularly benefit from implicit arguments since you call these functions frequently.
+
+6. Don't go wild with implicit parameters. Use them sparingly.
+
+## Migration from explicit arguments
+
+Existing code with explicit comparison functions will continue to work. You can adopt implicit arguments gradually:
+
+```motoko
+import Map "mo:core/Map";
+import Nat "mo:core/Nat";
+
+let data = Map.empty();
+
+// Both styles work simultaneously
+Map.add(data, Nat.compare, 1, "one");  // Explicit
+Map.add(data, 2, "two");                // Implicit
+Map.add(data, 3, "three");              // Implicit
+```
+
+There is no need to update existing code unless you want to take advantage of the cleaner syntax.
+
+## Performance considerations
+
+Implicit arguments have no runtime overhead. The comparison function is resolved at compile time, so there is no performance difference between using implicit and explicit arguments. The resulting code is identical.
+
+## See also
+
+- [Language reference](https://docs.motoko.org#function-calls)
diff --git a/docs/languages/motoko/fundamentals/imports.md b/docs/languages/motoko/fundamentals/imports.md
new file mode 100644
index 00000000..1ba12221
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/imports.md
@@ -0,0 +1,51 @@
+---
+sidebar_position: 2
+description: "Motoko language documentation"
+title: "Imports"
+hide_table_of_contents: true
+---
+
+In Motoko, related code modules are organized into packages. Modules can be imported either from named packages or from the local file system using relative paths. The compiler locates packages on the file system based on a command line argument specifying their location.
+
+Imports should be placed at the top of the source file. They enable code reuse from external libraries or modules, helping to improve maintainability and organization. You can import from:
+
+**1. Standard modules provided by the core package.**
+
+```motoko no-repl
+import Text "mo:core/Text";
+import Nat "mo:core/Nat";
+import Math "mo:core/Float";
+```
+
+The package `core` is Motoko's standard library.
+This imports the `Text`, `Nat` and `Float` modules from package `core` under the local names `Text`, `Nat` and `Math`.
+
+While not required, it's considered good practice to import a module using its package-defined name. This helps with consistency and readability across codebases.
+
+**2. Packages installed via a package manager (such as Mops).**
+
+```motoko no-repl
+import Iter "mo:itertools";
+```
+
+The module `Iter` is imported from a third-party package `itertools`.
+
+**3. Files within the current project.**
+
+```motoko no-repl
+import Utils "Utils";
+```
+
+**You can also import specific functions from a module:**
+
+```motoko no-repl
+import { compare } "mo:core/Nat";
+```
+
+**You can also import specific types from a module:**
+
+```motoko no-repl
+import { type Result; mapOk } "mo:core/Result";
+```
+
+Learn more about [modules and imports](/languages/motoko/fundamentals/imports).
diff --git a/docs/languages/motoko/fundamentals/literals.md b/docs/languages/motoko/fundamentals/literals.md
new file mode 100644
index 00000000..6b7e4e60
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/literals.md
@@ -0,0 +1,29 @@
+---
+sidebar_position: 6
+description: "Motoko language documentation"
+title: "Literals"
+hide_table_of_contents: true
+---
+
+Literals are constant expressions that require no further evaluation:
+
+- **Integer literals**: (Numbers, hexadecimal), such as: `42`, `109231`, `0x2A`
+
+- **Float literals**: (Floating point numbers), such as: `3.14`, `2.5e3`
+
+- **Character literals**: (Unicode characters), such as: `'A'`, `'J'`, `'✮'`
+
+- **Text literals**: `"Hello"`
+
+- **Blob literals**: Byte sequences using the same syntax as `Text`, such as: `"Motoko" : Blob` (interpreted as [UTF-8](https://en.wikipedia.org/wiki/UTF-8) when converted)
+
+You can use literals directly in expressions.
+
+```motoko
+100 + 50
+```
+
+## Resources
+
+- [Literals](https://docs.motoko.org#literals)
+
diff --git a/docs/languages/motoko/fundamentals/loops.md b/docs/languages/motoko/fundamentals/loops.md
new file mode 100644
index 00000000..5a851a1a
--- /dev/null
+++ b/docs/languages/motoko/fundamentals/loops.md
@@ -0,0 +1,183 @@
+---
+sidebar_position: 2
+description: "Motoko language documentation"
+title: "Loops"
+---
+
+
+
+In Motoko, loops provide flexible control over repetition, such as iterating over collections, looping while some condition holds, or just looping until an explicit exit from the loop.
+
+Motoko supports different types of loops:
+
+- `loop` loops: Repeat until explicitly exited.
+
+- `loop-while` loops: Repeat until condition is false (tests after each iteration).
+
+- `for` loops: Iteration over collections.
+
+- `while` loops: Repeat while condition is true (tests before each iteration).
+
+## Unconditional loops
+
+An unconditional loop runs indefinitely until it is explicitly stopped. Unlike `while` or `for` loops, which rely on a condition to determine when to exit, unconditional loops continue executing without any predefined exit condition. They are useful in scenarios where the program waits for an external event or depends on a break condition defined within the loop body.
+
+Motoko uses the `loop` keyword to define an infinite loop. To exit such a loop, you can use a `break` statement that will exit the innermost loop, or `break