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.
❌ 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
///| 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
///| /// 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
///| /// NG: ! suffix was removed assert_true!(true)
///| /// OK assert_true(true)
Multi-line Text
let text = #|line 1 #|line 2
Comments and Block Separators
///| is a block separator. /// comments attach to the following ///| block.
///| /// 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) .
test "snapshot" { inspect([1, 2, 3], content="") // auto-filled by moon test -u }
After running:
test "snapshot" { inspect([1, 2, 3], content="[1, 2, 3]") }
Doc Tests
Available in .mbt.md files or ///| inline comments.
Code Block Behavior
Checked by LSP
```mbt test
Executed as test {...}
```moonbit
Display only (not executed)
Example (inline comment):
///|
/// 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:
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
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.
# 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.
// 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.
///| 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