Enums - Ruchy Notebook - Language Proof
Description: Step-by-step empirical proof that all 41 Ruchy language features work in the notebook

# Enums - Feature 19/41

Enums (enumerations) define types with a fixed set of named variants. They're perfect for representing choices, states, and data that can be one of several options.

## Defining Enums

    enum Status {
      Pending,
      Active,
      Completed,
      Cancelled
    }

    enum Direction {
      North,
      South,
      East,
      West
    }

Test Coverage: ✅ tests/lang_comp/data_structures/enums.rs

### Try It in the Notebook

    enum Color {
      Red,
      Green,
      Blue
    }

    let color = Color::Red
    color  // Returns: Color::Red

Expected Output: `Color::Red`

## Using Enum Variants

Access variants with `::` notation:

    enum TrafficLight {
      Red,
      Yellow,
      Green
    }

    let light = TrafficLight::Red

Expected Output: `TrafficLight::Red`

## Pattern Matching with Enums

    enum Status {
      Pending,
      Active,
      Completed
    }

    fn describe_status(status) {
      match status {
        Status::Pending => "Not started yet",
        Status::Active => "Currently working",
        Status::Completed => "All done!"
      }
    }

    describe_status(Status::Active)  // Returns: "Currently working"

Expected Output: `"Currently working"`

## Enums with Data

Variants can hold data:

    enum Message {
      Quit,
      Move { x: i32, y: i32 },
      Write(String),
      ChangeColor(i32, i32, i32)
    }

    let msg1 = Message::Quit
    let msg2 = Message::Move { x: 10, y: 20 }
    let msg3 = Message::Write("Hello")
    let msg4 = Message::ChangeColor(255, 0, 0)

Expected Output: Various message types with data

### Pattern Matching with Data

    enum Message {
      Quit,
      Move { x: i32, y: i32 },
      Write(String)
    }

    fn process(msg) {
      match msg {
        Message::Quit => "Quitting",
        Message::Move { x, y } => f"Moving to ({x}, {y})",
        Message::Write(text) => f"Writing: {text}"
      }
    }

    process(Message::Move { x: 10, y: 20 })  // Returns: "Moving to (10, 20)"

Expected Output: `"Moving to (10, 20)"`

## Option Type

Built-in enum for optional values:

    enum Option<T> {
      Some(T),
      None
    }

    fn find(arr, target) {
      for item in arr {
        if item == target {
          return Some(item)
        }
      }
      None
    }

    let result = find([1, 2, 3], 2)
    match result {
      Some(value) => f"Found: {value}",
      None => "Not found"
    }
    // Returns: "Found: 2"

Expected Output: `"Found: 2"`

### Option Methods

    let some_value = Some(42)
    let no_value = None

    some_value.is_some()  // Returns: true
    some_value.is_none()  // Returns: false
    no_value.is_some()    // Returns: false
    no_value.is_none()    // Returns: true

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

### Unwrapping Option

    let value = Some(42)

    value.unwrap()           // Returns: 42
    value.unwrap_or(0)       // Returns: 42
    value.unwrap_or_else(|| 0)  // Returns: 42

    let none = None
    none.unwrap_or(0)        // Returns: 0

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

## Result Type

Built-in enum for operations that can fail:

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

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

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

Expected Output: `"Result: 5"`

### Result Methods

    let success = Ok(42)
    let failure = Err("error")

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

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

## Common Patterns

### State Machine

    enum State {
      Idle,
      Running,
      Paused,
      Stopped
    }

    fn transition(state, event) {
      match (state, event) {
        (State::Idle, "start") => State::Running,
        (State::Running, "pause") => State::Paused,
        (State::Paused, "resume") => State::Running,
        (State::Running, "stop") => State::Stopped,
        (State::Paused, "stop") => State::Stopped,
        _ => state  // No transition
      }
    }

    transition(State::Idle, "start")  // Returns: State::Running

Expected Output: `State::Running`

### HTTP Status

    enum HttpStatus {
      Ok,
      Created,
      BadRequest,
      Unauthorized,
      NotFound,
      InternalServerError
    }

    fn status_code(status) {
      match status {
        HttpStatus::Ok => 200,
        HttpStatus::Created => 201,
        HttpStatus::BadRequest => 400,
        HttpStatus::Unauthorized => 401,
        HttpStatus::NotFound => 404,
        HttpStatus::InternalServerError => 500
      }
    }

    status_code(HttpStatus::NotFound)  // Returns: 404

Expected Output: `404`

### JSON Value

    enum JsonValue {
      Null,
      Bool(bool),
      Number(f64),
      String(String),
      Array(Vec<JsonValue>),
      Object(HashMap<String, JsonValue>)
    }

    let data = JsonValue::Object({
      "name": JsonValue::String("Alice"),
      "age": JsonValue::Number(30),
      "active": JsonValue::Bool(true)
    })

Expected Output: Object with structured JSON data

### Command Pattern

    enum Command {
      Create { name: String },
      Update { id: i32, name: String },
      Delete { id: i32 },
      List
    }

    fn execute(cmd) {
      match cmd {
        Command::Create { name } => f"Creating {name}",
        Command::Update { id, name } => f"Updating {id} to {name}",
        Command::Delete { id } => f"Deleting {id}",
        Command::List => "Listing all items"
      }
    }

    execute(Command::Create { name: "Item" })  // Returns: "Creating Item"

Expected Output: `"Creating Item"`

## Enum Methods

Define methods on enums with `impl`:

    enum Status {
      Pending,
      Active,
      Completed
    }

    impl Status {
      fn is_done(&self) -> bool {
        match self {
          Status::Completed => true,
          _ => false
        }
      }

      fn message(&self) -> String {
        match self {
          Status::Pending => "Waiting to start",
          Status::Active => "In progress",
          Status::Completed => "Finished"
        }
      }
    }

    let status = Status::Active
    status.is_done()   // Returns: false
    status.message()   // Returns: "In progress"

Expected Output: `false`, `"In progress"`

## Recursive Enums

Enums can be recursive (with Box):

    enum List {
      Cons(i32, Box<List>),
      Nil
    }

    let list = List::Cons(1, Box::new(
      List::Cons(2, Box::new(
        List::Cons(3, Box::new(List::Nil))
      ))
    ))

Expected Output: Linked list: 1 -> 2 -> 3 -> Nil

## Enum Comparison

    enum Color {
      Red,
      Green,
      Blue
    }

    Color::Red == Color::Red    // Returns: true
    Color::Red == Color::Blue   // Returns: false

Expected Output: `true`, `false`

## Generic Enums

    enum Container<T> {
      Empty,
      Single(T),
      Multiple(Vec<T>)
    }

    let int_container = Container::Single(42)
    let str_container = Container::Multiple(["a", "b", "c"])

Expected Output: Containers with different types

## Best Practices

### ✅ Use Enums for Fixed Choices

    // Good: Clear, type-safe
    enum PaymentMethod {
      CreditCard,
      DebitCard,
      PayPal,
      BankTransfer
    }

    // Bad: String magic values
    let payment = "credit_card"  // Typos, no validation

### ✅ Prefer Pattern Matching

    // Good: Exhaustive, compiler-checked
    match status {
      Status::Pending => handle_pending(),
      Status::Active => handle_active(),
      Status::Completed => handle_completed()
    }

    // Bad: Multiple if-else
    if status == Status::Pending {
      handle_pending()
    } else if status == Status::Active {
      handle_active()
    } else {
      handle_completed()
    }

### ✅ Use Option Instead of Null

    // Good: Type-safe, forces handling
    fn find_user(id: i32) -> Option<User> {
      // ...
    }

    match find_user(123) {
      Some(user) => use_user(user),
      None => handle_not_found()
    }

    // Bad: Null values, runtime errors
    fn find_user(id: i32) -> User {
      // Returns null if not found - crashes!
    }

### ✅ Use Result for Error Handling

    // Good: Explicit error handling
    fn parse_int(s: String) -> Result<i32, String> {
      // Returns Ok(value) or Err(message)
    }

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

## Enums vs Structs

Feature | Enum | Struct
--- | --- | ---
Purpose | One of several variants | Group related fields
Variants | Multiple named options | Single structure
Data | Each variant can differ | All fields present
Matching | Pattern match on variant | Access fields directly
Use Case | States, choices, errors | Data models, entities

    // Enum: Represents one of several options
    enum Shape {
      Circle { radius: f64 },
      Rectangle { width: f64, height: f64 }
    }

    // Struct: Represents a single entity
    struct Point {
      x: f64,
      y: f64
    }

## Summary

✅ Feature Status: WORKING ✅ Test Coverage: 100% ✅ Mutation Score: 98%

Enums define types with fixed sets of variants, enabling type-safe state machines, error handling, and optional values. They're fundamental to Ruchy's type system.

Key Takeaways:

- Define variants with `enum Name { Variant1, Variant2 }`
- Access with `Name::Variant`
- Pattern match with `match`
- Built-in: `Option<T>` (Some/None), `Result<T, E>` (Ok/Err)
- Variants can hold data
- Better than magic values or null

← Previous: Structs | Next: Pattern Matching →