Why it matters
Callback hell in async code was a real productivity killer. Scala Futures solve it with monadic composition. Modern alternatives like Cats Effect IO or ZIO offer more, but Futures remain the standard for most async work.
The architecture
A Future[T] is a placeholder for a value of type T that will eventually exist. Creation via 'Future { block }' runs the block on the ExecutionContext and returns immediately with the Future.
Composition: '.map(f)' transforms the eventual value. '.flatMap(g)' chains another async operation. For-comprehensions provide sequential syntax over multiple Futures.
How it works end to end
ExecutionContext is the thread pool that runs Future computations. Global one exists for convenience; custom ones are essential for controlling blocking work vs CPU-bound work.
Error handling: Futures can complete with success or failure. 'recover' handles specific exceptions; 'recoverWith' does the same but returns another Future.
Blocking APIs inside Futures on the global context can starve it. Use blocking { ... } to signal blocking to the context, or use a dedicated pool.