Option Type - Feature 24/41

The Option type represents an optional value: either Some(value) or None. It eliminates null pointer errors by making absence explicit and type-safe.

Option Definition

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

Test Coverage: ✅ tests/lang_comp/error_handling/option.rs

Try It in the Notebook

let some_value = Some(42)
let no_value = None

some_value  // Returns: Some(42)
no_value    // Returns: None

Expected Output: Some(42), None

Creating Options

// Explicit construction
let name = Some("Alice")
let age = None

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

find([1, 2, 3], 2)  // Returns: Some(2)
find([1, 2, 3], 5)  // Returns: None

Expected Output: Some(2), None

Checking Option State

let value = Some(42)

value.is_some()  // Returns: true
value.is_none()  // Returns: false

let empty = None
empty.is_some()  // Returns: false
empty.is_none()  // Returns: true

Expected Output: true, false, false, true

Unwrapping Values

unwrap()

let value = Some(42)
value.unwrap()  // Returns: 42

let empty = None
empty.unwrap()  // Panics: "called unwrap() on None"

Expected Output: 42, then panic

unwrap_or()

let value = Some(42)
value.unwrap_or(0)  // Returns: 42

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

Expected Output: 42, 0

unwrap_or_else()

let value = Some(42)
value.unwrap_or_else(|| compute_default())  // Returns: 42

let empty = None
empty.unwrap_or_else(|| compute_default())  // Calls function

Expected Output: 42, result of compute_default()

Pattern Matching

let maybe_value = Some(42)

match maybe_value {
  Some(value) => f"Got {value}",
  None => "No value"
}
// Returns: "Got 42"

Expected Output: "Got 42"

If Let

let result = Some(42)

if let Some(value) = result {
  f"Value: {value}"
} else {
  "No value"
}
// Returns: "Value: 42"

Expected Output: "Value: 42"

Transforming Options

map()

let value = Some(42)
value.map(|x| x * 2)  // Returns: Some(84)

let empty = None
empty.map(|x| x * 2)  // Returns: None

Expected Output: Some(84), None

and_then()

let value = Some(42)
value.and_then(|x| {
  if x > 0 {
    Some(x * 2)
  } else {
    None
  }
})
// Returns: Some(84)

Expected Output: Some(84)

or()

let value = Some(42)
value.or(Some(0))  // Returns: Some(42)

let empty = None
empty.or(Some(0))  // Returns: Some(0)

Expected Output: Some(42), Some(0)

Common Patterns

Safe Array Access

fn get(arr, index) {
  if index >= 0 && index < arr.len() {
    Some(arr[index])
  } else {
    None
  }
}

get([1, 2, 3], 1)   // Returns: Some(2)
get([1, 2, 3], 10)  // Returns: None

Expected Output: Some(2), None

Dictionary Lookup

let users = {
  "alice": { name: "Alice", age: 30 },
  "bob": { name: "Bob", age: 25 }
}

fn find_user(users, username) {
  if users.has_key(username) {
    Some(users[username])
  } else {
    None
  }
}

find_user(users, "alice")  // Returns: Some({ name: "Alice", age: 30 })
find_user(users, "charlie")  // Returns: None

Expected Output: Some({ name: "Alice", age: 30 }), None

Null Coalescing

let config = {
  host: "localhost",
  port: None
}

let port = config.port.unwrap_or(8080)
port  // Returns: 8080

Expected Output: 8080

Chain Operations

fn parse_int(s) {
  // Returns Some(int) or None
}

fn double(n) {
  Some(n * 2)
}

let result = parse_int("42")
  .and_then(double)
  .unwrap_or(0)

result  // Returns: 84

Expected Output: 84

Option vs Null

FeatureOptionNull
Type SafetyExplicit in signatureHidden, runtime errors
Compiler CheckForces handlingSilent propagation
Default Valueunwrap_or(default)Manual checking
Chainingmap, and_thenRepeated null checks
IntentClear: may be absentAmbiguous: forgot to set?
// Option: Type-safe
fn find_user(id: i32) -> Option<User> {
  // ...
}

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

// Null: Unsafe
fn find_user(id: i32) -> User {
  // Returns null - crashes later!
}

let user = find_user(123)
user.name  // Crash if null!

Best Practices

✅ Use Option for Optional Values

// Good: Clear that value may be absent
fn find(arr, target) -> Option<i32> {
  // ...
}

// Bad: -1 means not found? Ambiguous!
fn find(arr, target) -> i32 {
  // Returns -1 on not found
}

✅ Prefer unwrap_or over unwrap

// Good: Safe default
let port = config.port.unwrap_or(8080)

// Bad: Panics if None
let port = config.port.unwrap()

✅ Use Pattern Matching

// Good: Explicit handling
match maybe_value {
  Some(value) => process(value),
  None => use_default()
}

// Bad: Risky unwrap
let value = maybe_value.unwrap()
process(value)

✅ Chain with map and and_then

// Good: Functional, clear
result
  .map(|x| x * 2)
  .and_then(validate)
  .unwrap_or(default)

// Bad: Nested if-let
if let Some(x) = result {
  let doubled = x * 2
  if let Some(valid) = validate(doubled) {
    valid
  } else {
    default
  }
} else {
  default
}

Summary

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

Option represents optional values type-safely, eliminating null pointer errors. Use Some(value) for presence, None for absence, and handle both cases explicitly.

Key Takeaways:

  • Some(value) vs None
  • Check state: is_some(), is_none()
  • Extract: unwrap(), unwrap_or(), unwrap_or_else()
  • Transform: map(), and_then(), or()
  • Pattern match for explicit handling
  • Better than null: type-safe, compiler-checked

← Previous: Try-Catch | Next: Result Type →