futures and promises
Order a coffee at a busy cafe and you get a buzzer. The coffee is not ready, but the buzzer is a real, holdable token that says 'a coffee will arrive here'. You can pocket it and go do something else; when it buzzes, you collect the drink. A future is that buzzer in code: a handle to a value that does not exist yet but will be filled in later. A promise is the matching half held by whoever is making the coffee: the write-end used to deliver the value (or an error) into the future.
Mechanically, a future and a promise share one piece of memory called the shared state. It holds three things: a slot for the result, a 'ready / not ready' flag, and a list of waiters. The producer holds the promise; when its work finishes it calls something like promise.set_value(x), which writes x into the shared state, flips the flag, and wakes anyone waiting. The consumer holds the future; calling future.get() either returns x immediately if ready, or blocks until the promise fills it. Crucially the two are split so the producer and consumer can run on different threads, decoupled in time — the consumer can ask for the value before it has been computed.
Futures matter because they give a name to an in-flight result, so you can pass it around, store it, and compose it before it is done. That is the foundation async/await and continuations are built on. Two honest distinctions: a future is read-only (you await it), a promise is write-once (you fulfil it exactly once). And futures come in two flavours — eager ones (C++ std::future, JavaScript Promises) where the work is already running, versus lazy ones (Rust's Future) which do nothing until an executor polls them. Confusing the two is a classic Rust beginner trap: an un-awaited Rust future is just a value that never runs.
C++: std::promise<int> p; std::future<int> f = p.get_future(); std::thread([&]{ p.set_value(42); }).detach(); int x = f.get(); // blocks until 42 arrives. The promise writes, the future reads, the shared state connects them.
One shared state, two handles: the promise is the write-end, the future is the read-end.
Naming is not universal: JavaScript's Promise is what most languages call a future (read side). And a Rust future is lazy — it runs nothing until polled by an executor; an eager C++ std::future is already executing. Do not assume one model.