Proposal: Introduce implicit raises for Optional Error Handling

Proposal: Introduce implicit raises for Optional Error Handling

Summary
I propose adding the syntax implicit raises Type. This allows functions to declare exceptions that are optional to handle. If the caller does not handle the exception (via try/except or raises), the program will abort (trap) at runtime upon error.

Motivation
Currently, errors in core operations (like index out-of-bounds[1] or out-of-memory) are hard-coded to trap. This lacks flexibility and forces library authors to maintain duplicate methods for different safety needs.

implicit raises improves this by:

  • Reducing API Surface Area: It eliminates the need for separate “safe” and “checked” variants of the same function (e.g., append vs checked_append). A single function definition serves both use cases.
  • Opt-in Error Handling: It defaults to ergonomic “abort on error” behavior for standard operations, but allows the caller to explicitly catch errors when recovery is required. This removes the need for verbose try blocks in simple scripts while allowing robustness in complex applications.
  • Pythonic feel: It moves closer to Python’s behavior where exceptions bubble up, while retaining Mojo’s systems-level safety defaults (aborting if unhandled).

Proposed Semantics
An implicit raises function behaves similarly to a standard raises function, with one key difference in caller responsibility:

  1. Handled: The caller may wrap the call in a try block to catch the specific error.
  2. Unhandled: The caller may call the function directly without a try block or raises propagation. If the error occurs, the program aborts (traps).

Examples

fn append(mut self, value: T) implicit raises OutOfMemoryError: ... 
fn __add__(lhs: Self, rhs: Self) implicit raises OverflowError -> Self: ...
fn __getitem__(self, index: Int) implicit raises IndexError -> T: ...

  1. Note: Bounds checks are currently active by default only in debug mode. ↩︎