# Lux: Vision and Roadmap ## The Problems Lux Solves ### 1. The "What Can This Code Do?" Problem In most languages, you can't tell from a function signature what it might do: ```typescript // TypeScript - what does this do? No idea without reading the code. function processOrder(order: Order): Receipt { ... } ``` Could it hit a database? Send emails? Log? Throw? You don't know until you read every line (and every function it calls). **Lux solution:** ```lux fn processOrder(order: Order): Receipt with {Database, Email, Logger, Fail} ``` The signature *is* the documentation. Code review becomes "should this function really send emails?" Effects are compile-time checked. ### 2. The Testing Problem Testing side-effecting code requires mocking frameworks, dependency injection containers, and boilerplate: ```typescript // TypeScript - need DI framework, mock libraries, setup/teardown const mockDb = jest.mock('./database'); const mockEmail = jest.mock('./email'); // ... 50 lines of setup ``` **Lux solution:** ```lux // Production run processOrder(order) with { Database = postgres(connString), Email = sendgrid(apiKey), Logger = cloudWatch } // Test - same code, different handlers run processOrder(order) with { Database = inMemoryDb(testData), Email = collectEmails(sentList), // captures instead of sends Logger = nullLogger } ``` No mocking library. No DI framework. Just swap handlers. ### 3. The Schema Evolution Problem (Planned) Types change. Data persists. Every production system eventually faces: - "I renamed this field, now deserialization breaks" - "I added a required field, old data can't load" - "I need to migrate 10M rows and pray" **Lux solution:** ```lux type User @v1 { name: String, email: String } type User @v2 { name: String, email: String, createdAt: Timestamp, from @v1 = { createdAt: Timestamp.epoch(), ..v1 } // migration } type User @v3 { fullName: String, // renamed email: String, createdAt: Timestamp, from @v2 = { fullName: v2.name, ..v2 } } // Compiler knows: v1 → v2 is auto-compatible, v2 → v3 needs migration // Serialization handles any version automatically ``` ### 4. The "Is This Safe?" Problem (Planned) Critical properties are documented in comments and hoped for: ```typescript // IMPORTANT: This function must be idempotent for retry logic! function chargeCard(payment: Payment): Result { ... } ``` **Lux solution:** ```lux fn chargeCard(payment: Payment): Result is idempotent // Compiler enforces or generates property tests ``` ```lux fn retry(action: F, times: Int): Result where F is idempotent // Won't compile if you pass non-idempotent function ``` --- ## What's Built vs. What's Needed ### Currently Working (Phase 1: Core Language) | Feature | Status | Notes | |---------|--------|-------| | Lexer/Parser | Done | Full syntax support | | Type Inference | Done | Hindley-Milner | | Functions/Closures | Done | First-class functions | | Pattern Matching | Done | Destructuring, guards | | Records/Tuples/Lists | Done | Basic data structures | | Effect Declarations | Done | `effect Name { ... }` | | Effect Operations | Done | `Effect.operation()` | | Effect Handlers | Done | `handler name: Effect { ... }` | | Run with Handlers | Done | `run expr with { ... }` | | Built-in Console/Fail | Done | Basic IO | | REPL | Done | Interactive development | | Type Checking | Done | With effect tracking | ### Completed (Phase 2: Practical) | Feature | Status | Notes | |---------|--------|-------| | **Module System** | ✅ Done | Imports, exports, aliases, selective imports | | **Standard Library** | ✅ Done | List, String, Option, Result, Math, Json modules | | **File Effect** | ✅ Done | read, write, exists, delete, listDir, mkdir | | **HTTP Client Effect** | ✅ Done | get, post, put, delete | | **HTTP Server Effect** | ✅ Done | listen, accept, respond, stop | | **Process Effect** | ✅ Done | exec, env, args, cwd, exit | | **Random/Time Effects** | ✅ Done | int, float, bool, now, sleep | | **JIT Compiler** | ✅ Partial | Numeric code ~160x faster, strings/ADTs pending | | **Error Messages** | ✅ Partial | Context lines shown, suggestions improving | ### In Progress (Phase 3: Differentiation) | Feature | Status | Notes | |---------|--------|-------| | **Schema Evolution** | ⚠️ Partial | Parsing done, type integration pending | | **Behavioral Types** | ⚠️ Partial | Parsing done, verification pending | | **LSP Server** | ✅ Done | Diagnostics, hover, completions working | | **Package Manager** | ⚠️ Partial | Manifest parsing exists | | **Effect Tracing** | Planned | Elm-like debugging | --- ## Elm-Style Debugging for Effects Elm's debugging is famous because: 1. **Time-travel**: See app state at any point 2. **No runtime crashes**: Everything is Result/Maybe 3. **Amazing error messages**: Context, suggestions, examples Lux can go further because effects are explicit: ### Effect Tracing Every effect operation can be automatically logged: ```lux // With tracing enabled: run processOrder(order) with { Database = traced(postgres), // Logs all queries Email = traced(sendgrid), // Logs all sends Logger = traced(cloudWatch) // Meta-logging! } // Output: // [00:00:01] Database.query("SELECT * FROM users WHERE id = 42") // [00:00:02] Database.query("SELECT * FROM inventory WHERE sku = 'ABC'") // [00:00:03] Email.send(to: "customer@example.com", subject: "Order Confirmed") // [00:00:03] Logger.log(level: "info", msg: "Order 123 processed") ``` ### Effect Replay Since all effects are captured, we can replay: ```lux // Record effects during production let recording = record(processOrder(order)) with { Database = postgres, ... } // Replay in development with exact same effect responses replay(recording) with { Database = mockFromRecording(recording) } ``` ### State Snapshots Since state changes only happen through effects: ```lux // Snapshot state before/after each effect run debugSession(app) with { State = snapshotted(initialState), // Captures every state change Console = traced(stdout) } // Later: inspect state at any point, step forward/backward ``` ### Error Messages (To Build) Current: ``` Type error at 15-45: Cannot unify Int with String ``` Goal (Elm-style): ``` ── TYPE MISMATCH ─────────────────────────────────────── src/order.lux The `calculateTotal` function expects an `Int` but got a `String`: 15│ let total = calculateTotal(order.quantity) ^^^^^^^^^^^^^^ `order.quantity` is a `String` but `calculateTotal` needs an `Int`. Hint: Maybe you need to parse the string? let qty = Int.parse(order.quantity)? let total = calculateTotal(qty) ``` --- ## Development Effort Summary **To be minimally useful for real projects:** - Module system + standard library + better errors - **Estimate: 6-8 weeks of focused work** **To deliver the full vision (effects + schemas + behavioral types):** - All of the above + schema evolution + behavioral types + compilation - **Estimate: 4-6 months of focused work** **To have Elm-quality experience:** - All of the above + debugging tools + LSP + package manager - **Estimate: 8-12 months of focused work** --- ## Immediate Next Steps 1. ~~**Standard Library**~~ - Done! List, String, Option, Result operations 2. ~~**Module System**~~ - Done! Imports, exports, aliases, selective imports 3. **File Effect** - `FileSystem.read`, `FileSystem.write` 4. **Error Message Overhaul** - Source snippets, suggestions, colors 5. **JavaScript Backend** - Compile to runnable JS These would make Lux usable for small real projects.