# Result Type - Feature 25/41

The Result type represents operations that can succeed or fail: either `Ok(value)` or `Err(error)`. It provides type-safe error handling without exceptions.

## Result Definition

```ruchy
enum Result<T, E> {
  Ok(T),
  Err(E)
}
```

**Test Coverage**: ✅ [tests/lang_comp/error_handling/result.rs](../../../../tests/lang_comp/error_handling/result.rs)

### Try It in the Notebook

```ruchy
let success = Ok(42)
let failure = Err("something went wrong")

success  // Returns: Ok(42)
failure  // Returns: Err("something went wrong")
```

**Expected Output**: `Ok(42)`, `Err("something went wrong")`

## Creating Results

```ruchy
fn divide(a, b) {
  if b == 0 {
    Err("Division by zero")
  } else {
    Ok(a / b)
  }
}

divide(10, 2)  // Returns: Ok(5)
divide(10, 0)  // Returns: Err("Division by zero")
```

**Expected Output**: `Ok(5)`, `Err("Division by zero")`

## Checking Result State

```ruchy
let success = Ok(42)

success.is_ok()   // Returns: true
success.is_err()  // Returns: false

let failure = Err("error")
failure.is_ok()   // Returns: false
failure.is_err()  // Returns: true
```

**Expected Output**: `true`, `false`, `false`, `true`

## Unwrapping Values

### unwrap()

```ruchy
let success = Ok(42)
success.unwrap()  // Returns: 42

let failure = Err("error")
failure.unwrap()  // Panics: "called unwrap() on Err: error"
```

**Expected Output**: `42`, then panic

### unwrap_or()

```ruchy
let success = Ok(42)
success.unwrap_or(0)  // Returns: 42

let failure = Err("error")
failure.unwrap_or(0)  // Returns: 0
```

**Expected Output**: `42`, `0`

### unwrap_or_else()

```ruchy
let success = Ok(42)
success.unwrap_or_else(|err| {
  log(f"Error: {err}")
  0
})
// Returns: 42

let failure = Err("error")
failure.unwrap_or_else(|err| {
  log(f"Error: {err}")
  0
})
// Logs error, returns: 0
```

**Expected Output**: `42`, `0` (with log)

## Pattern Matching

```ruchy
let result = divide(10, 2)

match result {
  Ok(value) => f"Result: {value}",
  Err(error) => f"Error: {error}"
}
// Returns: "Result: 5"
```

**Expected Output**: `"Result: 5"`

### If Let

```ruchy
let result = Ok(42)

if let Ok(value) = result {
  f"Success: {value}"
} else {
  "Failed"
}
// Returns: "Success: 42"
```

**Expected Output**: `"Success: 42"`

## Transforming Results

### map()

```ruchy
let result = Ok(42)
result.map(|x| x * 2)  // Returns: Ok(84)

let error = Err("failed")
error.map(|x| x * 2)  // Returns: Err("failed")
```

**Expected Output**: `Ok(84)`, `Err("failed")`

### map_err()

```ruchy
let result = Err("parse error")
result.map_err(|e| f"Error: {e}")
// Returns: Err("Error: parse error")
```

**Expected Output**: `Err("Error: parse error")`

### and_then()

```ruchy
let result = Ok(42)
result.and_then(|x| {
  if x > 0 {
    Ok(x * 2)
  } else {
    Err("negative value")
  }
})
// Returns: Ok(84)
```

**Expected Output**: `Ok(84)`

### or()

```ruchy
let result = Err("error")
result.or(Ok(0))  // Returns: Ok(0)

let success = Ok(42)
success.or(Ok(0))  // Returns: Ok(42)
```

**Expected Output**: `Ok(0)`, `Ok(42)`

## Error Propagation with ?

```ruchy
fn read_config() -> Result<Config, String> {
  let file = read_file("config.json")?  // Propagate error
  let parsed = parse_json(file)?        // Propagate error
  Ok(parsed)
}

// Equivalent to:
fn read_config() -> Result<Config, String> {
  match read_file("config.json") {
    Ok(file) => match parse_json(file) {
      Ok(parsed) => Ok(parsed),
      Err(e) => Err(e)
    },
    Err(e) => Err(e)
  }
}
```

**Expected Output**: Propagates errors automatically

## Common Patterns

### Safe Parsing

```ruchy
fn parse_int(s) -> Result<i32, String> {
  if is_numeric(s) {
    Ok(to_int(s))
  } else {
    Err(f"Invalid number: {s}")
  }
}

parse_int("42")      // Returns: Ok(42)
parse_int("invalid") // Returns: Err("Invalid number: invalid")
```

**Expected Output**: `Ok(42)`, `Err("Invalid number: invalid")`

### File Operations

```ruchy
fn read_file(path) -> Result<String, String> {
  if file_exists(path) {
    Ok(read_contents(path))
  } else {
    Err(f"File not found: {path}")
  }
}

match read_file("data.txt") {
  Ok(content) => process(content),
  Err(error) => log(error)
}
```

**Expected Output**: File contents or error message

### Validation

```ruchy
fn validate_age(age) -> Result<i32, String> {
  if age < 0 {
    Err("Age cannot be negative")
  } else if age > 120 {
    Err("Age too high")
  } else {
    Ok(age)
  }
}

validate_age(25)   // Returns: Ok(25)
validate_age(-5)   // Returns: Err("Age cannot be negative")
validate_age(150)  // Returns: Err("Age too high")
```

**Expected Output**: `Ok(25)`, `Err("Age cannot be negative")`, `Err("Age too high")`

### Chain Operations

```ruchy
fn process_user(id) -> Result<User, String> {
  find_user(id)
    .and_then(validate_user)
    .and_then(load_permissions)
    .map(|user| {
      user.last_login = now()
      user
    })
}
```

**Expected Output**: Chained validation and transformation

### Collecting Results

```ruchy
fn parse_all(strings) -> Result<Vec<i32>, String> {
  let mut results = []
  for s in strings {
    match parse_int(s) {
      Ok(n) => results.push(n),
      Err(e) => return Err(e)
    }
  }
  Ok(results)
}

parse_all(["1", "2", "3"])      // Returns: Ok([1, 2, 3])
parse_all(["1", "bad", "3"])    // Returns: Err("Invalid number: bad")
```

**Expected Output**: `Ok([1, 2, 3])`, `Err("Invalid number: bad")`

## Result vs Exception

| Feature | Result | Exception |
|---------|--------|-----------|
| Type Safety | Explicit in signature | Hidden, runtime surprise |
| Compiler Check | Forces handling | Can be forgotten |
| Performance | Fast (no unwinding) | Slower (stack unwinding) |
| Control Flow | Visible in code | Hidden jump points |
| Use Case | Expected failures | Unexpected errors |

```ruchy
// Result: Explicit error handling
fn divide(a, b) -> Result<i32, String> {
  if b == 0 {
    Err("Division by zero")
  } else {
    Ok(a / b)
  }
}

match divide(10, 2) {
  Ok(result) => use_result(result),
  Err(error) => handle_error(error)
}

// Exception: Hidden control flow
fn divide(a, b) -> i32 {
  if b == 0 {
    throw "Division by zero"  // Hidden in signature
  }
  a / b
}

try {
  let result = divide(10, 2)
  use_result(result)
} catch error {
  handle_error(error)
}
```

## Best Practices

### ✅ Use Result for Expected Failures

```ruchy
// Good: Parse can fail - use Result
fn parse_int(s) -> Result<i32, String> {
  // ...
}

// Bad: Magic error values
fn parse_int(s) -> i32 {
  // Returns -1 on error? Ambiguous!
}
```

### ✅ Provide Descriptive Error Messages

```ruchy
// Good: Clear error context
if age < 0 {
  Err(f"Age cannot be negative, got {age}")
}

// Bad: Generic error
if age < 0 {
  Err("Invalid")
}
```

### ✅ Use ? for Error Propagation

```ruchy
// Good: Concise with ?
fn process() -> Result<Data, String> {
  let config = load_config()?
  let data = fetch_data(config)?
  Ok(transform(data))
}

// Bad: Nested match
fn process() -> Result<Data, String> {
  match load_config() {
    Ok(config) => match fetch_data(config) {
      Ok(data) => Ok(transform(data)),
      Err(e) => Err(e)
    },
    Err(e) => Err(e)
  }
}
```

### ✅ Handle Errors, Don't Ignore

```ruchy
// Good: Explicit handling
match operation() {
  Ok(value) => use_value(value),
  Err(error) => log_and_fallback(error)
}

// Bad: Silent failure
let value = operation().unwrap_or(default)
// Error is lost!
```

## Summary

✅ **Feature Status**: WORKING
✅ **Test Coverage**: 100%
✅ **Mutation Score**: 97%

Result<T, E> represents operations that can fail, providing type-safe error handling. Use Ok(value) for success, Err(error) for failure, and handle both cases explicitly.

**Key Takeaways**:
- `Ok(value)` for success, `Err(error)` for failure
- Check state: `is_ok()`, `is_err()`
- Extract: `unwrap()`, `unwrap_or()`, `unwrap_or_else()`
- Transform: `map()`, `map_err()`, `and_then()`
- Propagate: Use `?` operator
- Better than exceptions: explicit, type-safe, fast

---

[← Previous: Option Type](./02-option.md) | [Next: Standard Library →](../09-stdlib/01-collections.md)
