# Chapter 5: Effects

This is where Lux gets interesting. Effects are the core innovation—they make side effects explicit, controllable, and composable.

## The Problem with Side Effects

In most languages, functions can do *anything*:

```javascript
// JavaScript - what does this do?
function process(x) {
    return x * 2;
}
```

It looks pure, but it could:
- Print to console
- Write to a file
- Make HTTP requests
- Throw exceptions
- Modify global state
- Launch missiles

You can't tell from the signature. You have to read the implementation.

## The Lux Solution

In Lux, effects are declared:

```lux
// Pure - only computes
fn double(x: Int): Int = x * 2

// Uses Console - you can see it
fn printDouble(x: Int): Unit with {Console} =
    Console.print(toString(x * 2))
```

The `with {Console}` tells you this function interacts with the console. It's part of the type.

## Built-in Effects

Lux provides several built-in effects:

| Effect | Operations | Purpose |
|--------|------------|---------|
| `Console` | `print`, `readLine`, `readInt` | Terminal I/O |
| `Fail` | `fail` | Early termination |
| `State` | `get`, `put` | Mutable state |
| `Random` | `int`, `float`, `bool` | Random numbers |
| `Time` | `now`, `sleep` | Time operations |
| `File` | `read`, `write`, `exists`, `delete`, `list`, `mkdir` | File system |
| `Process` | `exec`, `env`, `args`, `cwd`, `exit` | System processes |
| `Http` | `get`, `post`, `put`, `delete` | HTTP client |
| `HttpServer` | `listen`, `accept`, `respond`, `stop` | HTTP server |
| `Sql` | `open`, `openMemory`, `close`, `execute`, `query`, `queryOne`, `beginTx`, `commit`, `rollback` | SQLite database |
| `Postgres` | `connect`, `close`, `execute`, `query`, `queryOne` | PostgreSQL database |
| `Concurrent` | `spawn`, `await`, `yield`, `sleep`, `cancel`, `isRunning`, `taskCount` | Concurrent tasks |
| `Channel` | `create`, `send`, `receive`, `tryReceive`, `close` | Inter-task communication |
| `Test` | `assert`, `assertEqual`, `assertTrue`, `assertFalse` | Testing |

Example usage:

```lux
fn main(): Unit with {Console, Random} = {
    let n = Random.int(1, 100)
    Console.print("Random number: " + toString(n))
}

let output = run main() with {}
```

## Effect Propagation

Effects propagate up the call stack:

```lux
fn helper(): Int with {Console} = {
    Console.print("In helper")
    42
}

// Must declare Console because it calls helper
fn caller(): Int with {Console} = {
    let x = helper()
    x * 2
}

// Error: caller uses Console but doesn't declare it
fn broken(): Int = {
    caller()  // Error!
}
```

The rule: if you call a function with effect E, you must either:
1. Declare E in your signature
2. Handle E with a `run ... with {}` block

## Running Effects

The `run ... with {}` block executes effectful code:

```lux
fn greet(): Unit with {Console} =
    Console.print("Hello!")

// Execute with default handlers
let result = run greet() with {}
```

For built-in effects, `with {}` uses the default implementations (real console, real files, etc.).

## Custom Effects

You can define your own effects:

```lux
effect Logger {
    fn log(level: String, message: String): Unit
    fn getLevel(): String
}
```

This declares an effect with two operations. To use it:

```lux
fn processData(data: Int): Int with {Logger} = {
    Logger.log("info", "Starting processing")
    let result = data * 2
    Logger.log("debug", "Result: " + toString(result))
    result
}
```

But this won't run yet—we need a *handler*.

## Handlers

Handlers define how effect operations behave:

```lux
handler consoleLogger: Logger {
    fn log(level, message) = {
        Console.print("[" + level + "] " + message)
        resume(())
    }
    fn getLevel() = resume("debug")
}
```

Key concept: **`resume(value)`** continues the computation with `value` as the result of the effect operation.

Now we can run:

```lux
fn main(): Unit with {Console} = {
    let result = run processData(21) with {
        Logger = consoleLogger
    }
    Console.print("Final: " + toString(result))
}

let output = run main() with {}
```

Output:
```
[info] Starting processing
[debug] Result: 42
Final: 42
```

## The Power of Handlers

### Different Implementations

Same code, different behaviors:

```lux
// Console logging
handler consoleLogger: Logger {
    fn log(level, msg) = {
        Console.print("[" + level + "] " + msg)
        resume(())
    }
    fn getLevel() = resume("debug")
}

// Silent (for testing)
handler silentLogger: Logger {
    fn log(level, msg) = resume(())
    fn getLevel() = resume("none")
}

// Collecting logs
handler collectingLogger: Logger {
    fn log(level, msg) = {
        State.put(State.get() + "[" + level + "] " + msg + "\n")
        resume(())
    }
    fn getLevel() = resume("all")
}
```

### Resumable Operations

Unlike exceptions, handlers can *continue* the computation:

```lux
effect Ask {
    fn ask(prompt: String): String
}

fn survey(): String with {Ask} = {
    let name = Ask.ask("Name?")
    let age = Ask.ask("Age?")
    name + " is " + age + " years old"
}

// Handler that provides answers
handler mockAnswers: Ask {
    fn ask(prompt) =
        if String.contains(prompt, "Name") then resume("Alice")
        else resume("30")
}

run survey() with { Ask = mockAnswers }
// Returns: "Alice is 30 years old"
```

The computation pauses at `Ask.ask`, the handler provides a value, and `resume` continues from where it left off.

## Effect Composition

Multiple effects combine naturally:

```lux
fn program(): Int with {Console, Random, Logger} = {
    Logger.log("info", "Starting")
    let n = Random.int(1, 10)
    Console.print("Got: " + toString(n))
    Logger.log("debug", "Returning " + toString(n))
    n
}

let result = run program() with {
    Logger = consoleLogger
}
```

No monad transformers, no lifting, no complexity. Effects just work together.

## Why This Matters

### 1. Testability

```lux
// Production code
fn fetchUser(id: Int): String with {Http} =
    Http.get("https://api.example.com/users/" + toString(id))

// Test with mock HTTP
handler mockHttp: Http {
    fn get(url) = resume("{\"name\": \"Test User\"}")
    // ... other operations
}

// Test runs without network
let result = run fetchUser(1) with { Http = mockHttp }
```

### 2. Explicit Dependencies

```lux
// You can see exactly what this function needs
fn processOrder(order: Order): Receipt with {Database, Logger, Email}
```

### 3. Controlled Side Effects

```lux
// This function is pure - it CAN'T do I/O
fn calculateTotal(items: List<Item>): Int =
    List.fold(items, 0, fn(acc: Int, item: Item): Int => acc + item.price)

// Compile error if you try to add Console.print here
```

## Common Patterns

### Dependency Injection

```lux
effect Database {
    fn query(sql: String): List<Row>
    fn execute(sql: String): Int
}

fn getUsers(): List<User> with {Database} =
    Database.query("SELECT * FROM users")

// Production
handler postgresDb: Database { /* real implementation */ }

// Testing
handler mockDb: Database {
    fn query(sql) = resume([mockRow1, mockRow2])
    fn execute(sql) = resume(1)
}
```

### Configuration

```lux
effect Config {
    fn get(key: String): String
}

fn appUrl(): String with {Config} =
    Config.get("APP_URL")

handler envConfig: Config {
    fn get(key) = resume(Process.env(key))
}

handler testConfig: Config {
    fn get(key) = resume("http://localhost:8080")
}
```

### Early Return

```lux
fn validateUser(user: User): User with {Fail} = {
    if user.name == "" then Fail.fail("Name required")
    else if user.age < 0 then Fail.fail("Invalid age")
    else user
}

// Fail stops execution
let result = run validateUser(invalidUser) with {}
```

## Summary

| Concept | Syntax |
|---------|--------|
| Declare effect | `effect Name { fn op(): Type }` |
| Use effect | `fn f(): T with {Effect}` |
| Effect operation | `Effect.operation(args)` |
| Define handler | `handler name: Effect { fn op(...) = ... }` |
| Resume | `resume(value)` |
| Run with handler | `run expr with { Effect = handler }` |

## Next

[Chapter 6: Handlers](06-handlers.md) - Deep dive into handler patterns.
