Future
A Minimal, Typed Future Implementation inspired by the concept of Futures from the Rust Ecosystem.
Luau Futures
Futures are a Data-Driven approach to asynchronous calls, what this means is that Futures represent a value that does not exist quite yet, similar to Promises.
Unlike Promises, Futures take on a Data-Driven approach as opposed to a Event-Driven approach.
Futures have no events for you to react to, there is no andThen
or any other event-like methods
or functions for Futures.
In order to use Futures, you must do something called polling, you can call isReady
to see if the
future has a result ready, and then you can call output
to receive a result.
The future can either be ok or an error, you can use the ok
and error
methods respectively to check.
To get the value T
or Error
you can call the result as a function.
Why use this?
Don't. Use Promises. You shouldn't need to use this and shouldn't unless it fits a certain use case. Promises have Chaining, Joining, Cancellation, and many more features that Futures don't have.
Futures are simply a lightweight alternative to Promises that uses long polling. Any gains you may get from using Futures will be so insignificant you'd only be hurting yourself by using them in most cases.
See Roblox Lua Promise and Why Use Promises? by Evaera
Why I use Luau Futures
When writing code that ran every frame I found myself needing to represent yielding asynchronous calls in a way where I could store the future value and use it in a future frame. Promises felt like a good first step, but it just felt like they did not fit the Data-Driven architecture I was going for, with Promises being Event-Driven.
So here comes Luau Futures, a Data-Driven Approach to handling asynchronous code, built for a library such as Matter, which had no built-in method for handling Asynchronous Calls.
Basic Usage
local Future = require(path.to.module)
-- Create a future
local myFuture = Future(function(...)
-- Something that yields
end, ...)
-- Poll the Future to see if it is ready.
if myFuture:isReady() then
local result = myFuture:output()
local ... = result()
-- Do something
end
-- Poll the Future to see if it is still pending.
if myFuture:isPending() then
warn("Future is still pending!")
end
In a Matter System:
-- Basic concept of Futures in a Matter System
local function exampleSystem(world)
-- Create Futures
for id in world:query():without(Future) do
world:insert(id, Future {
future = Future(function()
-- Something that yields
end)
})
end
-- Poll Futures
for id, future in world:query(Future) do
local future = future.future
if future:isReady() then
local result = myFuture:output()
if result:ok() then
local returnedValues = result()
-- Do something
elseif result:error() then
warn(result())
end
world:remove(id, Future)
end
end
end
Installing with Wally
[dependencies]
Future = "yetanotherclown/future@1.0.0"
Note: Wally does not export types automatically and will display a type-error in one of the Dependencies. To fix this, see https://github.com/JohnnyMorganz/wally-package-types.
Building with Rojo
To build yourself, use:
rojo build -o "Future.rbxm"
For more help, check out the Rojo documentation.