Considered, not built: routes that carry a function
A design note from the engineering record, moved out of ROADMAP.md on 2026-09-03 and kept as written. The roadmap itself now holds only the project's state; the reasoning lives here.
Router.match returns an Int and the caller dispatches on it, which is why
three of five Mojo apps skip the router and hand-write if path == ….
Route-to-function is reachable on Mojo 1.0 — verified by spike, not
assumed. The spelling is thin: a closure trait (def (X) raises -> Y) is
an AnyTrait, refused as a List element and refused outright as a struct
field, but def (X) thin raises -> Y is a concrete type that lists and
struct fields both take, including generically —
List[def (mut Self.T, ...) thin raises -> HTTPResponse] inside a
struct RouteTable[T] dispatches and mutates T correctly.
What stopped it is a type cycle, not the language. Every Mojo app in this
tree keeps its state in the handler and the handler owns the router, so
RouteTable[NotesHandler] as a field of NotesHandler is infinitely
recursive. The fix is to split app state into a type the handler owns
alongside the table — a real design, and a real rewrite of the showcase app.
Building the table before an app wants it would add an API with zero call
sites, which is the condition auth.mojo and response_cache.mojo are
already in. Build it with the first app that asks; the spelling above is the
part that was unknown.