Error Handling
Understanding Walrus diagnostics: compile-time errors, intelligent suggestions, and runtime safety.
Walrus provides a robust diagnostic system designed to help you catch bugs early and fix them quickly. Errors in Walrus are split into two categories: Compile-time Diagnostics and Runtime Errors.
Compile-time Diagnostics
The Walrus compiler features a sophisticated diagnostic engine that provides clear, actionable feedback. When an error occurs, the compiler doesn't just stop; it often provides a snippet of your code with a marker and a helpful suggestion.
Source Snippets
Diagnostics include the filename, line number, and a visual marker pointing exactly to the problematic code.
main.wlrs:5:12: error: use of uninitialized variable 'player'
|
5 | print(player.name)
| ^^^^^^Intelligent Suggestions
The compiler includes a "Did you mean?" system that checks for typos in variable names, module members, and even compiler directives.
let counter = 10
print(countr) # error: unknown identifier 'countr'; did you mean 'counter'?Common suggestions include:
- Identifier Typos:
countr->counter - Directive Typos:
@stric->@strict - Missing Operators:
if x 10->did you mean a comparison like '<' or '=='? - Module Members:
Math.sqroot->Math.sqrt
Static Verification
Before your code runs, the Verifier performs a pass to ensure type safety and memory integrity.
Ownership Violations
Walrus will refuse to compile code that violates its memory safety rules. This prevents common bugs like "use-after-move" or conflicting borrows.
let text = "walrus"
let moved = text
print(text) # error: use of moved value 'text'Type Mismatches
Even though Walrus is dynamic in some areas, its static verifier catches obvious type mismatches:
- Assigning an
intto a variable expected to be anobject. - Passing the wrong number of arguments to a function.
- Returning a value that doesn't match the function's signature.
Runtime Errors
Some errors can only be caught while the script is running. When these occur, the VM throws a Runtime Error and stops execution safely.
Common runtime errors include:
- Division by Zero:
return 1 / 0 - Invalid Indexing: Accessing an array with a
boolor a string key that doesn't exist. - Native Handle Invalidation: Attempting to use a C++ object that the engine has already deleted.
- Null Access: Accessing a property on a
nilvalue.
Best Practices for Developers
- Read the Snippets: The markers (
^^^^) are calculated accurately. They often point to the exact sub-expression causing the issue. - Check Suggestions: The "Did you mean?" system uses Levenshtein distance to find the closest valid match. It's usually right!
- Strict Mode: Always use
@strictat the top of your modules. This enables extra compiler checks that catch common scripting mistakes. - Handle Native Safety: When working with engine objects, use
.is_valid()checks if you suspect the host engine might have deleted an object since you last used its handle.