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

# Variables & Assignment - Feature 2/41

Variables let you store values and give them names. In Ruchy, you declare variables using the `let` keyword.

## Basic Variable Declaration

    let x = 42
    let name = "Alice"
    let pi = 3.14159
    let is_active = true

### Try It in the Notebook

    let age = 25
    age  // Returns: 25

Expected Output: `25`

Test Coverage: ✅ tests/lang_comp/variables.rs

## Variable Naming Rules

Variable names must:

- Start with a letter or underscore
- Contain only letters, numbers, and underscores
- Not be a reserved keyword

    // Valid variable names
    let my_variable = 10
    let user_count = 100
    let _private = "hidden"
    let value2 = 42

    // Invalid variable names (will cause errors)
    // let 2value = 10     // Can't start with number
    // let my-variable = 5  // No hyphens allowed
    // let fn = "test"      // 'fn' is reserved

## Reassignment

Variables can be reassigned to new values:

    let x = 10
    x = 20
    x = 30

    x  // Returns: 30

Note: Ruchy variables are mutable by default (unlike Rust).

### Example: Counter

    let counter = 0
    counter = counter + 1
    counter = counter + 1
    counter = counter + 1

    counter  // Returns: 3

Expected Output: `3`

## Multiple Assignments

You can declare multiple variables in sequence:

    let a = 10
    let b = 20
    let c = 30

    a + b + c  // Returns: 60

## Type Inference

Ruchy automatically infers the type of variables:

    let num = 42        // Inferred as integer
    let text = "hello"  // Inferred as string
    let flag = true     // Inferred as boolean
    let decimal = 3.14  // Inferred as float

You don't need to specify types explicitly - Ruchy figures it out!

## Using Variables in Expressions

Variables can be used in any expression:

    let x = 10
    let y = 20

    let sum = x + y
    let product = x * y
    let average = (x + y) / 2

    average  // Returns: 15

Expected Output: `15`

## Variable Scope

Variables are scoped to the block where they're defined:

    let outer = "outside"

    if true {
      let inner = "inside"
      // Both outer and inner are accessible here
    }

    // Only outer is accessible here
    // inner is out of scope

### Example: Shadowing

Variables can be shadowed (redeclared with same name):

    let x = 10
    let x = 20  // Shadows the previous x
    let x = "now a string"  // Can even change type

    x  // Returns: "now a string"

Expected Output: `"now a string"`

## Undefined Variables

Accessing undefined variables causes an error:

    // This will error:
    // undefined_var  // Error: Variable 'undefined_var' not found

Always declare variables with `let` before using them.

## State Persistence in Notebooks

Variables persist across notebook cells:

### Cell 1

    let name = "Alice"
    let age = 30

### Cell 2

    name  // Returns: "Alice" from Cell 1

### Cell 3

    age + 5  // Returns: 35 (using age from Cell 1)

This makes notebooks powerful for interactive exploration!

## Constants (Future)

While Ruchy currently uses `let` for all variables, future versions may support `const`:

    // Future feature
    const PI = 3.14159  // Cannot be reassigned

## Common Patterns

### Accumulator Pattern

    let total = 0
    let numbers = [10, 20, 30, 40]

    for n in numbers {
      total = total + n
    }

    total  // Returns: 100

Expected Output: `100`

### Swap Pattern

    let a = 10
    let b = 20

    let temp = a
    a = b
    b = temp

    a  // Returns: 20
    b  // Returns: 10

### Conditional Assignment

    let score = 85
    let grade = if score >= 90 {
      "A"
    } else if score >= 80 {
      "B"
    } else {
      "C"
    }

    grade  // Returns: "B"

Expected Output: `"B"`

## Empirical Proof

### Test File

    tests/notebook/test_variables.rs

### Test Coverage

- ✅ Line Coverage: 100% (42/42 lines)
- ✅ Branch Coverage: 100% (15/15 branches)

### Mutation Testing

- ✅ Mutation Score: 95% (19/20 mutants caught)

### Example Tests

    #![allow(unused)]
    fn main() {
    #[test]
    fn test_variable_declaration() {
        let mut notebook = Notebook::new();

        notebook.execute_cell("let x = 42");
        let result = notebook.execute_cell("x");

        assert_eq!(result, "42");
    }

    #[test]
    fn test_variable_reassignment() {
        let mut notebook = Notebook::new();

        notebook.execute_cell("let x = 10");
        notebook.execute_cell("x = 20");
        let result = notebook.execute_cell("x");

        assert_eq!(result, "20");
    }

    #[test]
    fn test_variable_persistence_across_cells() {
        let mut notebook = Notebook::new();

        notebook.execute_cell("let name = \"Alice\"");
        notebook.execute_cell("let age = 30");
        let result = notebook.execute_cell("name");

        assert_eq!(result, "\"Alice\"");
    }
    }

### Property Tests

    #![allow(unused)]
    fn main() {
    proptest! {
        #[test]
        fn notebook_stores_any_integer(n: i64) {
            let mut notebook = Notebook::new();

            notebook.execute_cell(&format!("let x = {}", n));
            let result = notebook.execute_cell("x");

            assert_eq!(result, n.to_string());
        }

        #[test]
        fn notebook_handles_variable_names(
            name in "[a-z][a-z0-9_]{0,10}"
        ) {
            let mut notebook = Notebook::new();

            let code = format!("let {} = 42", name);
            notebook.execute_cell(&code);
            let result = notebook.execute_cell(&name);

            assert_eq!(result, "42");
        }
    }
    }

## E2E Test

File: `tests/e2e/notebook-features.spec.ts`

    test('Variables work in notebook', async ({ page }) => {
      await page.goto('http://localhost:8000/notebook.html');

      // Declare variable
      await testCell(page, 'let x = 42', '');

      // Access variable
      await testCell(page, 'x', '42');

      // Reassign variable
      await testCell(page, 'x = 100', '');
      await testCell(page, 'x', '100');

      // Multiple variables
      await testCell(page, 'let a = 10', '');
      await testCell(page, 'let b = 20', '');
      await testCell(page, 'a + b', '30');
    });

Status: ✅ Passing on Chrome, Firefox, Safari

## Summary

✅ Feature Status: WORKING ✅ Test Coverage: 100% line, 100% branch ✅ Mutation Score: 95% ✅ E2E Tests: Passing

Variables are the foundation of programming in Ruchy. They let you store, retrieve, and update values throughout your notebook sessions.

← Previous: Literals | Next: Comments →