> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ton.org/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/tolk/idioms-conventions",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Idioms and conventions

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

After learning of [basic syntax](/languages/tolk/basic-syntax), study the common patterns, conventions, and best practices to write idiomatic Tolk code.

## Prefer automatic serialization to manual one

Manual work with slices and builders is error-prone and tedious. By comparison, [auto-serialization](/languages/tolk/features/auto-serialization) with structures helps express data with types and prevents many related bugs.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct Holder {
    owner: address
    lastUpdated: uint32
    extra: Cell<ExtraInfo>
}

fun demo(data: Holder) {
    // make a cell with 299 bits and 1 ref
    val c = data.toCell();

    // unpack it back
    val holder = Holder.fromCell(c);
}
```

## Prefer typed cells with `Cell<T>`

All data in TON is stored in cells. To express data relation clearly and to aid in [serialization](/languages/tolk/features/auto-serialization#controlling-cell-references-typed-cells), use cells with well-typed contents: `Cell<T>`.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct Holder {
    // ...
    extra: Cell<ExtraInfo>
}

struct ExtraInfo {
    someField: int8
    // ...
}

fun getDeepData(value: Holder) {
    // `value.extra` is a reference
    // use `load()` to access its contents
    val data = value.extra.load();
    return data.someField;
}
```

## Use lazy data loading

When reading data from cells, add the [`lazy` keyword](/languages/tolk/features/lazy-loading):

* `lazy SomeStruct.fromCell(c)` over `SomeStruct.fromCell(c)`
* `lazy typedCell.load()` over `typedCell.load()`

With `lazy`, the compiler loads only the requested fields, skipping the rest. This reduces gas consumption and bytecode size:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
get fun publicKey() {
    val st = lazy Storage.load();
    // <-- here, "skip 65 bits, preload uint256" is inserted
    return st.publicKey
}
```

## Use type aliases to express custom serialization logic

Serialization may require custom rules which are not covered by existing types. Tolk allows defining custom [serialization rules for type aliases](/languages/tolk/types/overall-serialization#type-aliases):

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
// The custom type alias over a regular, untyped slice
type MyString = slice

// The function that is called when composing a new cell with a builder
fun MyString.packToBuilder(self, mutate b: builder) {
    // ...custom logic for MyString serialization
}

// The function that is called when loading data from the cell with a slice
fun MyString.unpackFromSlice(mutate s: slice) {
    // ...custom logic for MyString deserialization
}

// With those two functions implemented, MyString becomes
// a type with clear serialization rules and can be used anywhere
struct Everywhere {
    tokenName: MyString
    fullDomain: Cell<MyString>
}
```

Consider a structure that holds a signature hash of the data in its tail:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct SignedRequest {
    signature: uint256
    // hash of all data below is signed
    field1: int32
    field2: address?
    // ...
}
```

The task is to parse the structure and check the signature of the fields below `signature` against it. A manual approach would be to read `uint256`, calculate the hash of the remaining slice, then read other fields and compare the signatures.

However, a better solution is to continue using auto-serialization by introducing a synthetic field populated only when loading a slice and never when composing a cell with a builder:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
type HashOfRemainder = uint256

struct SignedRequest {
    signature: uint256
    restHash: HashOfRemainder // populated on load
    field1: int32
    field2: address?
    // ...
}

fun HashOfRemainder.unpackFromSlice(mutate s: slice) {
    // In this case, `s` is a slice remainder after loading `signature`,
    // while the `restHash` field has to contain the hash of that remainder:
    return s.hash()
}

// Now, assert that signatures match
fun demo(input: slice) {
    val req = SignedRequest.fromSlice(input);
    assert (req.signature == req.restHash) throw XXX;
}
```

## Use contract storage as a structure

[Contract storage](/languages/tolk/features/contract-storage) is a regular `struct`, serialized into persistent on-chain data.

Add `load` and `store` methods for convenience:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct Storage {
    counterValue: int64
}

fun Storage.load() {
    return Storage.fromCell(contract.getData())
}

fun Storage.save(self) {
    contract.setData(self.toCell())
}
```

## Express messages as structs with 32-bit prefixes

By convention, every message in TON has an *opcode*: a unique 32-bit number. In Tolk, every [`struct`](/languages/tolk/syntax/structures-fields) can have a serialization prefix of arbitrary length. Use 32-bit prefixes to express message opcodes.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct (0x12345678) CounterIncrement {
    // ...message body fields...
}
```

When implementing [Jettons](/standard/tokens/jettons/overview), [NFTs](/standard/tokens/nft/overview), or other standard contracts, use predefined opcodes according to the specification. Otherwise, opcodes are ad hoc.

## Use unions to handle incoming messages

The suggested pattern:

1. Each [incoming message](/languages/tolk/features/message-handling) is made a struct with an opcode.
2. Structs are combined into a union type.
3. Union is used to lazily load data from the message body slice.
4. Finally, result is [pattern matched](/languages/tolk/syntax/pattern-matching) over union variants.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct (0x12345678) CounterIncrement {
    incBy: uint32
}

struct (0x23456789) CounterReset {
    initialValue: int64
}

type AllowedMessage = CounterIncrement | CounterReset

fun onInternalMessage(in: InMessage) {
    val msg = lazy AllowedMessage.fromSlice(in.body);
    match (msg) {
        CounterIncrement => {
            // use `msg.incBy`
        }
        CounterReset => {
            // use `msg.initialValue`
        }
        else => {
            // invalid input; a typical reaction is:
            // ignore empty messages, "wrong opcode" if not
            assert (in.body.isEmpty()) throw 0xFFFF
        }
    }
}
```

The `lazy` keyword works with unions and performs a lazy match by the slice prefix: a message opcode. This approach is more efficient than manual opcode parsing and branching via a series of `if (op == TRANSFER_OP)` statements.

## Use structs to send messages

To send a message from contract A to contract B:

1. Declare a struct with an opcode and fields expected by the receiver.
2. Use the `createMessage()` function to compose a message, and the `send()` method to send it.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct (0x98765432) RequestedInfo {
    // ...
}

fun respond(/* ... */) {
    val reply = createMessage({
        bounce: BounceMode.NoBounce,
        value: ton("0.05"),
        dest: addressOfB,
        body: RequestedInfo {
            // ... initialize fields
        }
    });
    reply.send(SEND_MODE_REGULAR);
}
```

<Aside type="tip">
  When both contracts share the same codebase, a struct serves as an outgoing message for A and an incoming message for B.
</Aside>

## Attach initial code and data to a message to deploy another contract

Contract deployment is performed by attaching the code and data of the future contract to a message sent to its soon-to-be-initialized address. That address is deterministically calculated from the attached code and data.

A common case is when the jetton minter contract deploys a jetton wallet contract per user, knowing the future wallet's initial state: code and data.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
val msgThatDeploys = createMessage({
    // address auto-calculated, code+data auto-attached
    dest: {
        // initial state
        stateInit: {
            code: jettonWalletCode,
            data: emptyWalletStorage.toCell(),
        }
    }
});
```

Since one cannot synchronously check whether a contract is already deployed, the standard approach is always to attach the initial state needed for deployment whenever the contract's logic requires it.

To calculate or validate resulting addresses in addition to sending messages to them, always extract the `StateInit` generation to a separate function:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
fun calcDeployedJettonWallet(/* ... */): AutoDeployAddress {
    val emptyWalletStorage: WalletStorage = {
        // ... initialize fields from parameters
    };

    return {
        stateInit: {
            code: jettonWalletCode,
            data: emptyWalletStorage.toCell()
        }
    }
}

fun demoDeploy() {
    val deployMsg = createMessage({
        // address auto-calculated, code+data auto-attached
        dest: calcDeployedJettonWallet(...),
        // ...
    });
    deployMsg.send(mode);
}
```

<Aside type="tip">
  See the [Tolk contract examples](/languages/tolk/examples#jetton) page for selected contracts from the [`tolk-bench`](https://github.com/ton-blockchain/tolk-bench).
</Aside>

## Target certain shards when deploying sibling contracts

Specify the prefix length and the contract address to aim for the [same shard](/languages/tolk/features/message-sending#shard-based-deployment). For example, sharded jetton wallet must be deployed to the same shard as the owner's wallet.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
val deployMsg = createMessage({
    dest: {
        stateInit: { code, data },
        toShard: {
            closeTo: ownerAddress,
            fixedPrefixLength: 8
        }
    }
});
```

## Emit events and logs to off-chain world during development

[External messages](/languages/tolk/features/message-sending#universal-createexternallogmessage) with a special address `none` are used to emit events and logs to the outer world. Indexers catch such messages and provide a picture of on-chain activity.

External messages cost less gas than internal ones and help track events during contract development. They provide a simple way to emit structured logs that indexers and debugging tools can consume.

To send an external log message:

1. Create a `struct` to represent the message body.
2. Use `createExternalLogMessage()` to compose a message and the `send()` method to send it.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct DepositEvent {
    // ...fields...
}

fun demo() {
    val emitMsg = createExternalLogMessage({
        dest: createAddressNone(),
        body: DepositEvent {
            // ...field values...
        }
    });
    emitMsg.send(SEND_MODE_REGULAR);
}
```

## Return several state values as a structure from a get method

When a [contract getter](/languages/tolk/features/contract-getters) needs to return several values, introduce a structure. Avoid returning unnamed tensors like `(int, int, int)`. Field names provide clear metadata for client wrappers and human readers.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct JettonWalletDataReply {
    jettonBalance: coins
    ownerAddress: address
    minterAddress: address
    jettonWalletCode: cell
}

get fun get_wallet_data(): JettonWalletDataReply {
    return {
        jettonBalance: ...,
        ownerAddress: ...,
        minterAddress: ...,
        jettonWalletCode: ..,
    }
}
```

## Validate user input with assertions

After parsing an incoming message, validate required fields with [`assert`](/languages/tolk/syntax/exceptions#assert-statement):

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
assert (msg.seqno == storage.seqno) throw E_INVALID_SEQNO;
assert (msg.validUntil > blockchain.now()) throw E_EXPIRED;
```

If a condition is violated, execution terminates with the specified error code. Otherwise, a contract remains ready to serve the next request. This is the standard mechanism for reacting to invalid input.

## Organize a project into several files

Consistent file structure across projects simplifies navigation:

* Supply `errors.tolk` with constants or enums.
* Supply `storage.tolk` with storage and helper methods.
* Supply `messages.tolk` with incoming and outgoing messages.
* Have `some-contract.tolk` as an entrypoint. Keep entrypoint files minimal, use [imports](/languages/tolk/syntax/imports) to bring all supplementary code.

When developing several related contracts simultaneously, keep them in the same codebase. For instance, struct `SomeMessage`, outgoing for contract A, can be incoming for contract B. In other cases,  contract A must know B's storage to assign the initial state for deployment.

## Prefer methods to functions

All symbols across different files share the same namespace and must have unique names project-wide. There are no modules or exports.

Use [methods](/languages/tolk/syntax/functions-methods) to avoid name collisions:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
fun Struct1.validate(self) { /* ... */ }
fun Struct2.validate(self) { /* ... */ }
```

Methods are also more convenient: `obj.someMethod()` reads better than `someFunction(obj)`.

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct AuctionConfig {
    // ...fields...
}

// Prefer this:
fun AuctionConfig.isInvalid(self) {
    // ...
}

// Over this:
// fun isAuctionConfigInvalid(config: AuctionConfig) {}
```

Static methods follow the same pattern: `Auction.createFrom(...)` reads better than `createAuctionFrom(...)`.

A method without a `self` parameter is static:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
fun Auction.createFrom(config: cell, minBid: coins) {
    // ...
}
```

Static methods also group utility functions. For example, standard functions like `blockchain.now()` are static methods on an empty struct. This technique emulates namespaces:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
struct blockchain

fun blockchain.now(): int /* ... */;
fun blockchain.logicalTime(): int /* ... */;
```

## Use optional addresses to have address defaults

A nullable [address](/languages/tolk/types/address) `address?` is a pattern for an optional address, sometimes called *"maybe address"*:

* `null` represents the address `none`.
* `address` represents an internal address.

## Calculate CRC32 or SHA256 at compile-time

Several [compile-time methods](/languages/tolk/types/strings#compile-time-methods) operate on constant [strings](/languages/tolk/types/strings):

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
// Calculates CRC32 of a string
const crc32 = "some_str".crc32()

// Calculates SHA256 of a string as a 256-bit integer
const hash = "some_crypto_key".sha256()
```

## Work with strings

Tolk provides a dedicated [`string` type](/languages/tolk/types/strings) backed by snake-encoded cells. Use the [`StringBuilder`](/languages/tolk/types/strings#stringbuilder) for concatenation:

```tolk theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import "@stdlib/strings"

var str = StringBuilder.create()
         .append("hello ")
         .append("world")
         .build();
```

For fixed-size binary data, use [`bitsN` or `bytesN` types](/languages/tolk/types/cells#fixed-size-slices).

## Avoid micro-optimization

The [compiler applies many optimizations](/languages/tolk/features/compiler-optimizations): it automatically inlines functions, reduces stack allocations, and handles the underlying work. Attempts to outsmart the compiler yield negligible effects, either positive or negative.

Prefer readability over manual optimizations:

* Use one-line methods freely as they are auto-inlined.
* Use flat structures: they are as efficient as raw stack values.
* Extract standalone values into constants and variables.
* Avoid assembler functions unless necessary.
