# Future / Promise Pattern

## Problem

A caller initiates an asynchronous operation but needs the result later. Without a mechanism to represent the pending result, the caller must either block immediately or manage callbacks manually, leading to tangled control flow.

## Solution

Return a **Future** (or **Promise**) object that acts as a placeholder for a value that will be available later. The caller can continue other work and retrieve the result when needed, either by awaiting it or registering a callback.

## When to Use

- Any asynchronous I/O operation (HTTP calls, database queries, file reads)
- Parallelizing independent computations and combining results
- Building composable async pipelines
- When you need cancellation or timeout on pending operations

## When to Avoid

- Purely synchronous code with no latency
- Simple fire-and-forget operations where the result is never needed
- When the overhead of the Future wrapper exceeds the operation cost

## Pseudocode

```
function fetchData(url):
    return Future(() => http_get(url))

future1 = fetchData("https://api/users")
future2 = fetchData("https://api/orders")

// Do other work while requests are in flight...

users = await future1
orders = await future2
print("Users: " + users + ", Orders: " + orders)
```

## Python

```python
import asyncio
import time

async def fetch_data(name: str, delay: float) -> str:
    print(f"[{name}] Starting fetch...")
    await asyncio.sleep(delay)
    result = f"{name}_data"
    print(f"[{name}] Fetch complete: {result}")
    return result

async def main() -> None:
    # Create futures (tasks)
    future_users = asyncio.ensure_future(fetch_data("users", 0.3))
    future_orders = asyncio.ensure_future(fetch_data("orders", 0.2))
    future_products = asyncio.ensure_future(fetch_data("products", 0.1))

    print("Futures created, doing other work...")

    # Await all results
    users, orders, products = await asyncio.gather(
        future_users, future_orders, future_products
    )

    print(f"Results: users={users}, orders={orders}, products={products}")

    # Demonstrate sequential chaining
    combined = await fetch_data("combined", 0.1)
    print(f"Chained result: {combined}")

if __name__ == "__main__":
    asyncio.run(main())
```

## Go

```go
package main

import (
	"fmt"
	"time"
)

// Future represents an asynchronous result
type Future[T any] struct {
	ch chan T
}

func NewFuture[T any](fn func() T) *Future[T] {
	f := &Future[T]{ch: make(chan T, 1)}
	go func() {
		f.ch <- fn()
	}()
	return f
}

func (f *Future[T]) Get() T {
	return <-f.ch
}

func fetchData(name string, delay time.Duration) *Future[string] {
	return NewFuture(func() string {
		fmt.Printf("[%s] Starting fetch...\n", name)
		time.Sleep(delay)
		result := name + "_data"
		fmt.Printf("[%s] Fetch complete: %s\n", name, result)
		return result
	})
}

func main() {
	futureUsers := fetchData("users", 300*time.Millisecond)
	futureOrders := fetchData("orders", 200*time.Millisecond)
	futureProducts := fetchData("products", 100*time.Millisecond)

	fmt.Println("Futures created, doing other work...")

	users := futureUsers.Get()
	orders := futureOrders.Get()
	products := futureProducts.Get()

	fmt.Printf("Results: users=%s, orders=%s, products=%s\n", users, orders, products)
}
```

## JavaScript

```javascript
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function fetchData(name, delayMs) {
  console.log(`[${name}] Starting fetch...`);
  await sleep(delayMs);
  const result = `${name}_data`;
  console.log(`[${name}] Fetch complete: ${result}`);
  return result;
}

async function main() {
  // Create promises (start immediately)
  const promiseUsers = fetchData("users", 300);
  const promiseOrders = fetchData("orders", 200);
  const promiseProducts = fetchData("products", 100);

  console.log("Promises created, doing other work...");

  // Await all results
  const [users, orders, products] = await Promise.all([
    promiseUsers,
    promiseOrders,
    promiseProducts,
  ]);

  console.log(`Results: users=${users}, orders=${orders}, products=${products}`);

  // Chaining with .then()
  const chained = await fetchData("combined", 100).then((data) => {
    console.log(`Chained transform: ${data.toUpperCase()}`);
    return data.toUpperCase();
  });
  console.log(`Final chained: ${chained}`);
}

main();
```

## Related Patterns

- **Observer** — futures can be composed with observer-style callbacks (`.then()`) triggered on completion.
- **Monad** — futures/promises form a monad; chaining `.then()` is equivalent to monadic bind.
- **Active Object** — the active object pattern uses futures to decouple method invocation from execution.
