No null, no exceptions
A missing value is an Option, a failure is a Result, and match makes you handle both arms. Errors are ordinary values you pass around like any other data.
The compiler, dev server with hot reload, formatter, test runner, and language server live in one small binary. There is nothing else to install and nothing to configure. Update any time with vilan upgrade.
macOS / Linux
Windows (PowerShell)
Homebrew
A view is a value and a binding is a subscription: bind_text sets the text node once, then sets it again whenever the signal changes. There is no virtual DOM, no render loop, and no dependency array to babysit. Updates land exactly where the data changed.
The snippet is the whole program, and it runs. Try it right here:
clicked 0 times
import std::ui::{ view, mount_root };import std::reactive::Signal;fun main() {let count = Signal::new(0);let _root = mount_root("app", || {view("div").child(view("p").bind_text(count.map(|n: i32| i"clicked {n} times"))).child(view("button").text("+1").on("click", || count.set_with(|n| n + 1)))});}
the write
the signal
the one text node
no virtual DOM, no re-render: the subscription updates exactly one node
Mark a method [rpc] and the browser can call it like any other function, typed and checked. Mark a signal [expose] and every connected client holds a live mirror that updates when the server writes. You never write REST endpoints, fetch calls, or the JSON shapes that drift out of sync between them.
notes.vl · one source
notes.add("ship it")
entries
mirrored live
one definition: the compiler builds both sides and keeps them honest
import std::io::print;import std::option::Option::{ self, Some, None };fun find_user(id: i32): Option<str> {if id == 1 { Some("Ada") } else { None }}fun greet(name: str): str {i"hello {name}"}fun main() {print(greet(find_user(2)));}
Error: Expected str, but got Option<str> instead.╭─[ demo.vl:10:14 ]│10 │ print(greet(find_user(2)));│ ──────┬────│ ╰─────── Expected str, but got Option<str> instead.────╯
Vilan has no null and no exceptions. A value that might be missing is an Option, a call that might fail returns a Result, and the compiler makes you look inside before you use either. The mistake in this snippet is a build error, not a production incident.
Values are copied rather than silently shared, so two names never fight over one object. Most of the mistakes JavaScript saves for runtime cannot even be written.
Option & Result in the referencevilan and vilan-lsp ship together so your editor and build never disagree. In-editor diagnostics, hover types and docs, autocompletion, Symbol Rename, formatting, and Organize Imports are all available in VS Code today.
One broken line does not take the tooling down. The rest of the file keeps compiling, serving hovers, and completing while you fix it.
The VS Code extensionA missing value is an Option, a failure is a Result, and match makes you handle both arms. Errors are ordinary values you pass around like any other data.
Assignment copies. Sharing is explicit, borrowing is checked, and spooky action at a distance is a compile error.
docsawait is implicit. Call an async function and the machinery is the compiler's problem. When you want real concurrency, tasks and nurseries give it structure.
docsOne workspace compiles the node server and the browser client. The compiler tracks which code needs which platform and keeps each bundle honest.
docsstd::ui renders on the server too: first paint is real markup, then the client rebuilds it live. View source on this page and the content is already there.
vilan run . --watch rebuilds in milliseconds and hot-reloads the browser. Format, test, and language server ship in the same binary.
This site is a vilan program: one package, three entries — this page, the playground, and the server that renders both. The server rendered the markup you first saw, and the browser rebuilt it live.
Vilan is built to last. Semantics are settled on paper before they are implemented, and pinned by tests after. A language is a foundation, and a foundation should not move under you.