---
name: moonbit-practice
description: MoonBit code generation best practices. Use when writing MoonBit code to avoid common AI mistakes with syntax, tests, and benchmarks.
---

# MoonBit Practice Guide

Best practices for AI when generating MoonBit code.
If you don't understand something here, use `moonbit-docs` skill to search the official documentation.

## Guidelines

### Code Navigation: Prefer moon ide over Read/Grep

In MoonBit projects, **prefer `moon ide` commands over Read tool or grep**.

```bash
# ❌ Avoid: Reading files directly
Read src/parser.mbt

# ✅ Recommended: Find definitions from symbols
moon ide peek-def Parser::parse
moon ide goto-definition -tags 'pub fn' -query 'parse'

# ❌ Avoid: Searching with grep
grep -r "fn parse" .

# ✅ Recommended: Semantic search
moon ide find-references parse
moon ide outline src/parser.mbt
```

**Why:**

- `moon ide` provides semantic search (distinguishes definitions from call sites)
- grep picks up comments and strings
- `moon doc` quickly reveals APIs

### Other Rules

- Use `moon doc '<Type>'` to explore APIs before implementing
- Check reference/configuration.md before editing moon.pkg.json / moon.mod.json
- Check reference/agents.md when updating CLAUDE.md

## Common Pitfalls

- **Don't use uppercase for variables/functions** - compilation error
- **`mut` is only for reassignment, not field mutation** - Array push doesn't need it
- **`return` is unnecessary** - last expression is the return value
- **Methods require `Type::` prefix**
- **`++` `--` not supported** - use `i = i + 1` or `i += 1`
- **No `try` needed for error propagation** - automatic (unlike Swift)
- **No `await` keyword** - just declare with `async fn`
- **Prefer range for over C-style** - `for i in 0..<n {...}`
- **Legacy syntax**: `function_name!(...)` and `function_name(...)?` are deprecated

## Common Syntax Mistakes by AI

### Type Parameter Position

```moonbit
///| NG: fn identity[T] is old syntax
fn identity[T](val: T) -> T { val }

///| OK: Type parameter comes right after fn
fn[T] identity(val: T) -> T { val }
```

### raise Syntax

```moonbit
///|
/// NG: -> T!Error was removed
fn parse(s: String) -> Int!Error { ... }

///|
/// OK: Use raise keyword
fn parse(s: String) -> Int raise Error { ... }
```

`Int raise` is shorthand for `Int raise Error`.
async fn implicitly raises by default; use `noraise` to enforce no errors.

### Macro Calls

```moonbit
///|
/// NG: ! suffix was removed
assert_true!(true)

///|
/// OK
assert_true(true)
```

### Multi-line Text

```moonbit
let text =
  #|line 1
  #|line 2
```

### Comments and Block Separators

`///|` is a block separator. `///` comments attach to the following `///|` block.

```moonbit
///|
/// This function is foo
fn foo() -> Unit { ... }

///|
/// This function is bar
fn bar() -> Unit { ... }
```

Avoid consecutive `///|` at the file beginning as they create separate blocks.

## Snapshot Tests

`moon test -u` auto-updates `content=""` in `inspect(val)`.

```moonbit
test "snapshot" {
  inspect([1, 2, 3], content="")  // auto-filled by moon test -u
}
```

After running:

```moonbit
test "snapshot" {
  inspect([1, 2, 3], content="[1, 2, 3]")
}
```

## Doc Tests

Available in `.mbt.md` files or `///|` inline comments.

| Code Block       | Behavior                    |
| ---------------- | --------------------------- |
| ` ```mbt check ` | Checked by LSP              |
| ` ```mbt test `  | Executed as `test {...}`    |
| ` ```moonbit `   | Display only (not executed) |

Example (inline comment):

````moonbit

///|
/// Increment an integer by 1
/// ```mbt test
/// inspect(incr(41), content="42")
/// ```
pub fn incr(x : Int) -> Int {
  x + 1
}
````

## Pre-release Checklist

Run before releasing:

```bash
moon fmt   # Format code
moon info  # Generate type definition files
```

`pkg.generated.mbti` is auto-generated by `moon info`. Don't edit it directly.

## Exploring Built-in Type Methods

```bash
moon doc StringView   # StringView methods
moon doc Array        # Array methods
moon doc Map          # Map methods
```

## Quick Reference

| Topic            | Command                     | Details                                                    |
| ---------------- | --------------------------- | ---------------------------------------------------------- |
| Test             | `moon test`                 | https://docs.moonbitlang.com/en/stable/language/tests      |
| Update snapshots | `moon test -u`              | Same as above                                              |
| Filtered test    | `moon test --filter 'glob'` | Run specific tests                                         |
| Benchmark        | `moon bench`                | https://docs.moonbitlang.com/en/stable/language/benchmarks |
| Doc Test         | `moon check` / `moon test`  | https://docs.moonbitlang.com/en/stable/language/docs       |
| Format           | `moon fmt`                  | -                                                          |
| Generate types   | `moon info`                 | -                                                          |
| Doc reference    | `moon doc <Type>`           | -                                                          |

## moon ide Tools

More accurate than grep for code navigation. See `reference/ide.md` for details.

```bash
# Show symbol definition
moon ide peek-def Parser::read_u32_leb128

# Package outline
moon ide outline .

# Find references
moon ide find-references TranslationUnit

# Jump to type definition (with location)
moon ide peek-def Parser -loc src/parse.mbt:46:4
```

## Functional for loop

Prefer functional for loops whenever possible. More readable and easier to reason about.

```moonbit
// Functional for loop with state
for i = 0, sum = 0; i <= 10; {
  continue i + 1, sum + i  // Update state
} else {
  sum  // Value at loop exit
}

// Range for (recommended)
for i in 0..<n { ... }
for i, v in array { ... }  // index and value
```

## Error Handling

MoonBit uses checked errors. See `reference/ffi.md` for details.

```moonbit
///| Declare error type
suberror ParseError {
  InvalidEof
  InvalidChar(Char)
}

///| Declare with raise, auto-propagates
fn parse(s: String) -> Int raise ParseError {
  if s.is_empty() { raise ParseError::InvalidEof }
  ...
}

///| Convert to Result
let result : Result[Int, ParseError] = try? parse(s)

///| Handle with try-catch
parse(s) catch {
  ParseError::InvalidEof => -1
  _ => 0
}
```

## Assets

assets/ci.yaml is a GitHub Actions workflow for CI
