# Result Type

## Problem

Exceptions are invisible in function signatures. Callers don't know what can fail or forget to handle errors. `None`/`null` return values lose error context. Error codes are easy to ignore. You need a way to make success and failure explicit in the type system so that callers are forced to handle both cases.

## Solution

Return a **Result** (also called Either, or Go's `(value, error)` tuple) that wraps either a success value or an error. The caller must inspect the result before accessing the value, making error handling explicit and compiler/linter-checkable.

```
Result<T, E> = Ok(T) | Err(E)
```

## When to Use

- Functions that can fail in expected ways (I/O, parsing, validation).
- APIs where callers must handle errors — not silently ignore them.
- Languages without exceptions (Go, Rust) or when you want to avoid exception-based flow.

## When to Avoid

- Truly exceptional, unrecoverable situations (out of memory, corrupted state) — let those panic/crash.
- Simple scripts where try/except is clearer and shorter.
- When the language ecosystem strongly favours exceptions (e.g., idiomatic Java).

## Pseudocode

```
function divide(a, b):
    if b == 0:
        return Err("division by zero")
    return Ok(a / b)

result = divide(10, 0)
match result:
    Ok(value): print("Result:", value)
    Err(error): print("Error:", error)
```

## Python

```python
"""Result Type pattern in Python."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Generic, TypeVar, Union

T = TypeVar("T")
E = TypeVar("E")


# ── Result type ───────────────────────────────────────────────

@dataclass(frozen=True)
class Ok(Generic[T]):
    value: T

    @property
    def is_ok(self) -> bool:
        return True

    @property
    def is_err(self) -> bool:
        return False

    def unwrap(self) -> T:
        return self.value

    def unwrap_err(self):
        raise RuntimeError("Called unwrap_err on Ok")


@dataclass(frozen=True)
class Err(Generic[E]):
    error: E

    @property
    def is_ok(self) -> bool:
        return False

    @property
    def is_err(self) -> bool:
        return True

    def unwrap(self):
        raise RuntimeError(f"Called unwrap on Err: {self.error}")

    def unwrap_err(self) -> E:
        return self.error


Result = Union[Ok[T], Err[E]]


# ── Functions that return Results ─────────────────────────────

def divide(a: float, b: float) -> Result[float, str]:
    if b == 0:
        return Err("division by zero")
    return Ok(a / b)


def parse_int(s: str) -> Result[int, str]:
    try:
        return Ok(int(s))
    except ValueError:
        return Err(f"cannot parse '{s}' as integer")


def safe_pipeline(raw: str, divisor: float) -> Result[float, str]:
    """Chain multiple Result-returning operations."""
    parsed = parse_int(raw)
    if parsed.is_err:
        return parsed  # propagate error

    divided = divide(parsed.unwrap(), divisor)
    if divided.is_err:
        return divided  # propagate error

    return Ok(divided.unwrap() * 2)


# ── Tests ─────────────────────────────────────────────────────

def test_divide_success():
    result = divide(10, 3)
    assert result.is_ok
    print(f"PASS: 10/3 = {result.unwrap():.4f}")


def test_divide_by_zero():
    result = divide(10, 0)
    assert result.is_err
    assert result.unwrap_err() == "division by zero"
    print(f"PASS: 10/0 -> Err(\"{result.unwrap_err()}\")")


def test_parse_valid():
    result = parse_int("42")
    assert result.is_ok and result.unwrap() == 42
    print(f"PASS: parse '42' -> Ok({result.unwrap()})")


def test_parse_invalid():
    result = parse_int("abc")
    assert result.is_err
    print(f"PASS: parse 'abc' -> Err(\"{result.unwrap_err()}\")")


def test_pipeline_success():
    result = safe_pipeline("100", 5)
    assert result.is_ok and result.unwrap() == 40.0
    print(f"PASS: pipeline('100', 5) -> Ok({result.unwrap()})")


def test_pipeline_parse_error():
    result = safe_pipeline("xyz", 5)
    assert result.is_err
    print(f"PASS: pipeline('xyz', 5) -> Err(\"{result.unwrap_err()}\")")


def test_pipeline_divide_error():
    result = safe_pipeline("100", 0)
    assert result.is_err
    print(f"PASS: pipeline('100', 0) -> Err(\"{result.unwrap_err()}\")")


if __name__ == "__main__":
    test_divide_success()
    test_divide_by_zero()
    test_parse_valid()
    test_parse_invalid()
    test_pipeline_success()
    test_pipeline_parse_error()
    test_pipeline_divide_error()
    print("\nAll Result Type tests passed.")
```

## Go

```go
// result_type.go — Go uses (value, error) tuples idiomatically
package main

import (
	"fmt"
	"strconv"
)

// ── Functions returning (value, error) ───────────────────────

func divide(a, b float64) (float64, error) {
	if b == 0 {
		return 0, fmt.Errorf("division by zero")
	}
	return a / b, nil
}

func parseInt(s string) (int, error) {
	n, err := strconv.Atoi(s)
	if err != nil {
		return 0, fmt.Errorf("cannot parse '%s' as integer", s)
	}
	return n, nil
}

func safePipeline(raw string, divisor float64) (float64, error) {
	parsed, err := parseInt(raw)
	if err != nil {
		return 0, err
	}

	divided, err := divide(float64(parsed), divisor)
	if err != nil {
		return 0, err
	}

	return divided * 2, nil
}

// ── Tests ────────────────────────────────────────────────────

func testDivideSuccess() {
	val, err := divide(10, 3)
	if err != nil {
		panic(err)
	}
	fmt.Printf("PASS: 10/3 = %.4f\n", val)
}

func testDivideByZero() {
	_, err := divide(10, 0)
	if err == nil {
		panic("expected error")
	}
	fmt.Printf("PASS: 10/0 -> error(\"%v\")\n", err)
}

func testParseValid() {
	val, err := parseInt("42")
	if err != nil || val != 42 {
		panic("parse failed")
	}
	fmt.Printf("PASS: parse '42' -> %d\n", val)
}

func testParseInvalid() {
	_, err := parseInt("abc")
	if err == nil {
		panic("expected error")
	}
	fmt.Printf("PASS: parse 'abc' -> error(\"%v\")\n", err)
}

func testPipelineSuccess() {
	val, err := safePipeline("100", 5)
	if err != nil || val != 40.0 {
		panic("pipeline failed")
	}
	fmt.Printf("PASS: pipeline('100', 5) -> %.1f\n", val)
}

func testPipelineDivideError() {
	_, err := safePipeline("100", 0)
	if err == nil {
		panic("expected error")
	}
	fmt.Printf("PASS: pipeline('100', 0) -> error(\"%v\")\n", err)
}

func main() {
	testDivideSuccess()
	testDivideByZero()
	testParseValid()
	testParseInvalid()
	testPipelineSuccess()
	testPipelineDivideError()
	fmt.Println("\nAll Result Type tests passed.")
}
```

## JavaScript

```javascript
// result_type.js — Result/Either pattern in JavaScript

// ── Result type ──────────────────────────────────────────────

class Ok {
  constructor(value) {
    this.value = value;
  }
  get isOk() {
    return true;
  }
  get isErr() {
    return false;
  }
  unwrap() {
    return this.value;
  }
  unwrapErr() {
    throw new Error("Called unwrapErr on Ok");
  }
}

class Err {
  constructor(error) {
    this.error = error;
  }
  get isOk() {
    return false;
  }
  get isErr() {
    return true;
  }
  unwrap() {
    throw new Error(`Called unwrap on Err: ${this.error}`);
  }
  unwrapErr() {
    return this.error;
  }
}

// ── Functions returning Results ──────────────────────────────

function divide(a, b) {
  if (b === 0) return new Err("division by zero");
  return new Ok(a / b);
}

function parseInt_(s) {
  const n = Number(s);
  if (isNaN(n) || !Number.isInteger(n))
    return new Err(`cannot parse '${s}' as integer`);
  return new Ok(n);
}

function safePipeline(raw, divisor) {
  const parsed = parseInt_(raw);
  if (parsed.isErr) return parsed;

  const divided = divide(parsed.unwrap(), divisor);
  if (divided.isErr) return divided;

  return new Ok(divided.unwrap() * 2);
}

// ── Tests ────────────────────────────────────────────────────

function testDivideSuccess() {
  const result = divide(10, 3);
  console.assert(result.isOk);
  console.log(`PASS: 10/3 = ${result.unwrap().toFixed(4)}`);
}

function testDivideByZero() {
  const result = divide(10, 0);
  console.assert(result.isErr);
  console.log(`PASS: 10/0 -> Err("${result.unwrapErr()}")`);
}

function testParseValid() {
  const result = parseInt_("42");
  console.assert(result.isOk && result.unwrap() === 42);
  console.log(`PASS: parse '42' -> Ok(${result.unwrap()})`);
}

function testParseInvalid() {
  const result = parseInt_("abc");
  console.assert(result.isErr);
  console.log(`PASS: parse 'abc' -> Err("${result.unwrapErr()}")`);
}

function testPipelineSuccess() {
  const result = safePipeline("100", 5);
  console.assert(result.isOk && result.unwrap() === 40);
  console.log(`PASS: pipeline('100', 5) -> Ok(${result.unwrap()})`);
}

function testPipelineDivideError() {
  const result = safePipeline("100", 0);
  console.assert(result.isErr);
  console.log(`PASS: pipeline('100', 0) -> Err("${result.unwrapErr()}")`);
}

testDivideSuccess();
testDivideByZero();
testParseValid();
testParseInvalid();
testPipelineSuccess();
testPipelineDivideError();
console.log("\nAll Result Type tests passed.");
```

## Related Patterns

- **Monad** — Result is a monad; chaining `map`/`and_then` operations on Result is monadic composition.
- **Null Object** — Null Object silently ignores errors; Result Type makes errors explicit and forces handling.
- **Guard Clause** — guard clauses return early with errors; they can return Result types instead of throwing exceptions.
- **Pattern Matching** — use pattern matching to destructure Ok/Err variants and handle both cases explicitly.
