<!-- Generated from content/docs/whats-new-0-5.md; edit the source file instead. -->

# What's new in Nybl 0.5

Nybl 0.5 is a breaking release. All crates move together to `0.5.0`:

```toml
[dependencies]
nybl = { package = "nybl-lang", version = "0.5" }
nybl-vm = "0.5"       # optional bytecode engine
nybl-compile = "0.5"  # optional AOT transpiler
nybl-sys = "0.5"      # optional OS-backed host
```

The release bounds the native stack an execution can use, so a host can size
its threads from Nybl's limits; shares resource accounting between a program
and the modules it loads; and turns flat-import name clashes from warnings into
errors.

## Import name clashes are errors

In 0.4, two glob imports that introduced the same name kept the first binding
and printed a warning to stderr. In 0.5 a glob or selective `use` that would
bind a name the scope already binds to a different declaration — a `let`,
parameter, module alias, `fn`, type, built-in type, or another import — fails:

```nybl
use money
use ledger           // both export `helper`
```

```
error: `helper` is already defined — `use ledger` would import a different `helper`
```

A `fn` declared after a flat `use` bound its name fails too:
`` `helper` is already imported from `money` — `fn helper` would replace it ``.

Importing the same declaration twice (a diamond re-export, or a selective
import followed by a glob of the same module) is fine, a later `let` still
shadows an import, and `use path as alias` is unaffected. The runtime warning
is gone; static-check warnings are unchanged. See
[Modules → Name clashes](https://nybl-lang.com/docs/modules/index.html.md#name-clashes).

## Chains count toward the parse cap

The parser's 128-level nesting cap now counts each link of an operator or
postfix chain — `a + b + ...`, `x[0][0]...`, `.m().m()...`, `f(1)(2)...`.
Code past the cap is rejected with `Code is nested too deeply`. Programs with
very long chains may need splitting across `let` bindings. See
[Parse and nesting limits](https://nybl-lang.com/docs/errors/index.html.md#parse-and-nesting-limits).

## Nesting budget

`NyblLimits` has a new field, `max_nesting` (default
`nybl::DEFAULT_MAX_NESTING`, 2048, in both presets):

```rust
let limits = NyblLimits::standard().with_max_nesting(512);
```

Every active function, lambda, or method body, loading module top level, and
the root program charge their static nesting depth. Exceeding the budget is an
ordinary, `try_call`-catchable error,
`Too much nested code across active function calls`, raised at the same call in
the walker, VM, and sandboxed AOT.

## Modules share the run's limits

A module load is one call frame. Call depth (64), the nesting budget, and the
step budget are shared between an importer and the modules it loads in every
engine; the VM previously restarted its step counter in each module. Loading a
module also costs one step per token of its source, charged at the `use` line
the first time it is imported. See
[Modules share the limits](https://nybl-lang.com/docs/embedding/index.html.md#modules-share-the-limits).

## Bounded native stack

With the parse cap, call-depth cap, and nesting budget together, a thread with
a 10 MiB stack (release builds) or 128 MiB (debug builds) is enough for any
program under default limits. Embedders should run scripts on threads at least
that large; `nybl run` and the REPL now do. See
[Thread stack size](https://nybl-lang.com/docs/embedding/index.html.md#thread-stack-size).

## Migrating from 0.4

- Change dependency requirements from `"0.4"` to `"0.5"`.
- Resolve the name clashes the new errors report: import only the names you
  need (`use money.{total}`), namespace the module (`use money as m`), or
  rename the local declaration.
- Add `max_nesting` to any `NyblLimits { .. }` literal that lists every field,
  or spread `..NyblLimits::standard()`.
- Run scripts on a thread of the documented stack size.
- Split expressions whose operator or postfix chains exceed 128 links.
- Hand-built `nybl_vm` bytecode must set the new `Chunk::nesting_depth` and
  `FnDef::checks_import_clash` fields.

The repository's `CHANGELOG.md` lists the full release notes.
