Future::Q(3pm)
πΈ NAME β Future::Q(3pm) πΈ
okay bestie, this is Future::Q from User Contributed Perl Documentation, and it's literally a Future (or Promise or Deferred) like Q module for JavaScript. π No cap.
β¨ SYNOPSIS β¨
okay so here's the whole vibe in code, bestie π
use Future::Q;
sub async_func_future {
my @args = @_;
my $f = Future::Q->new;
other_async_func( ## This is a regular callback-style async function
args => \@args,
on_success => sub { $f->fulfill(@_) },
on_failure => sub { $f->reject(@_) },
);
return $f;
}
async_func_future()->then(sub {
my @results = @_;
my @processed_values = do_some_processing(@results);
return @processed_values;
})->then(sub {
my @values = @_; ## same values as @processed_values
return async_func_future(@values);
})->then(sub {
warn "Operation finished.\n";
})->catch(sub {
## failure handler
my $error = shift;
warn "Error: $error\n";
});
π¦ DESCRIPTION π¦
Future::Q is a subclass of Future. It extends its API with then() and try() etc, and those are almost completely compatible with Kris Kowal's Q module for JavaScript. periodt. π
Future::Q's API and documentation is designed to be self-contained, at least for basic usage of Futures. If a certain function you want is missing in this module, you should refer to "Missing Methods and Features" section and/or Future. (But be prepared because Future has a lot of methods!) π
Basically a Future (in a broad meaning) represents an operation (whether it's in progress or finished) and its results. It is also referred to as "Promise" or "Deferred" in other contexts. For further information as to what Future is all about, see:
Futureβ the base classPromisesβ another Future/Promise/Deferred implementation with pretty good documentationQβ JavaScript module, athttp://documentup.com/kriskowal/q/
π Terminology of Future States π
Any Future::Q object is in one of the following four states. vibe check: π
pendingβ The operation represented by theFuture::Qobject is now in progress.fulfilledβ The operation has succeeded and theFuture::Qobject has its results. The results can be obtained byget()method.rejectedβ The operation has failed and theFuture::Qobject has the reason of the failure. The reason of the failure can be obtained byfailure()method.cancelledβ The operation has been cancelled.
The state transition is one-way; pending -> fulfilled, pending -> rejected or pending -> cancelled. Once the state moves to a non-pending state, its state never changes anymore. iykyk.
In the terminology of Future, "done" and "failed" are used for "fulfilled" and "rejected", respectively.
You can check the state of a Future::Q with predicate methods is_pending(), is_fulfilled(), is_rejected() and is_cancelled().
π« then() Method π«
Using then() method, you can register callback functions with a Future::Q object. The callback functions are executed when the Future::Q object is fulfilled or rejected. You can obtain and use the results of the Future::Q within the callbacks. obsessed. π
The return value of then() method represents the results of the callback function (if it's executed). Since the callback function is also an operation in progress, the return value of then() is naturally a Future::Q object. By calling then() method on the returned Future::Q object, you can chain a series of operations that are executed sequentially. the way that chains is iconic. β¨
See the specification of then() method below for details.
π¨ Reporting Unhandled Failures π¨
Future::Q warns you when a rejected Future::Q object is destroyed without its failure handled. This is because ignoring a rejected Future::Q is just as dangerous as ignoring a thrown exception. Any rejected Future::Q object must be handled properly. fr fr. π«Ά
By default when a rejected but unhandled Future::Q is destroyed, the reason of the failure is printed through Perl's warning facility. This behavior can be modified by setting $OnError package variable (see below).
Future::Q thinks failures of the following futures are "handled". bestie, write this down: π
- Futures that
then(),catch()orfinally()method has been called on. - Futures returned by
$on_fulfilledor$on_rejectedcallbacks forthen()orcatch()method. - Futures returned by
$callbackforfinally()method. - Subfutures given to
wait_all(),wait_any(),needs_all()andneeds_any()method. - Futures given to another Future's
resolve()method as its single argument.
So make sure to call catch() method at the end of any callback chain to handle failures.
I also recommend always inspecting failed subfutures using failed_futures() method in callbacks for dependent futures returned by wait_all(), wait_any(), needs_all() and needs_any(). This is because there may be multiple of failed subfutures. It is even possible that some subfutures fail but the dependent future succeeds.
π§ PACKAGE VARIABLES π§
You can set the following package variables to change Future::Q's behavior. slay. π
π $OnError π
A subroutine reference called when a rejected but unhandled Future::Q object is destroyed.
$OnError is called like
$OnError->($warning_message)
The $warning_message can be evaluated to a human-readable string (It IS a string actually, but this may change in future versions). So you can pass the string to a logger, for example.
my $logger = ...;
$Future::Q::OnError = sub {
my ($warning_message) = @_;
$logger->warn("Unhanlded Future: " . $warning_message);
};
If $OnError is "undef", which is the default, $warning_message is printed by the built-in warn() function. You can capture it by setting $SIG{__WARN__}.
π CLASS METHODS π
In addition to all class methods in Future, Future::Q has the following class methods. main character energy only. π
π $future = Future::Q->new() π
Constructor. It creates a new pending Future::Q object.
π₯ $future = Future::Q->try($func, @args) / $future = Future::Q->fcall($func, @args) π₯
Immediately executes the $func with the arguments @args, and returns a Future object that represents the result of $func.
fcall() method is an alias of try() method.
$func is a subroutine reference. It is executed with the optional arguments @args.
The return value ($future) is determined by the following rules:
- If
$funcreturns a single Future object,$futureis that object. - If
$functhrows an exception,$futureis a rejectedFuture::Qobject with that exception. The exception is never rethrown to the upper stacks. - Otherwise,
$futureis a fulfilledFuture::Qobject with the values returned by$func.
If $func is not a subroutine reference, it returns a rejected Future::Q object. noted, bestie. π
β¨ OBJECT METHODS β¨
okay so on top of literally every object method you already get from Future, Future::Q also gives you these ones. bestie, there's a lot, but we're gonna get through it together π«Ά
π¦ $next_future = $future->then([$on_fulfilled, $on_rejected])
Registers callback functions that fire when $future is fulfilled or rejected, and hands you back a shiny new Future::Q object that represents the result of the whole operation. literally the whole vibe β¨
π Difference from then() method of Future
Future::Q overrides the then() method of the base Future class. lowkey they behave the same way, but in Future::Q's then():
- the callback funcions do not have to return a
Futureobject. If they don't, the return values are automatically transformed into a fulfilledFuture::Qobject. no cap π - it will not warn you even if you call the
then()method in void context. it's just chill like that.
(yes, "funcions" is a typo, and no, we're not fixing it β it's iconic, it's part of the lore π )
π Detailed specification
Below is the detailed spec of the then() method, so pay attention bestie π
$on_fulfilled and $on_rejected are subroutine references. When $future is fulfilled, the $on_fulfilled callback is executed. Its arguments are the values of the $future, which you get via the $future->get method. When $future is rejected, the $on_rejected callback is executed. Its arguments are the reason of the failure, obtained via the $future->failure method. Both $on_fulfilled and $on_rejected are optional β you can pass one, both, or neither π«
$next_future is a new Future::Q object. In a nutshell, it represents the result of $future plus whatever happened when $on_fulfilled or $on_rejected ran afterwards.
In detail, the state of $next_future is decided by these rules π
- While
$futureis pending,$next_futureis pending. - When
$futureis cancelled, neither$on_fulfillednor$on_rejectedis executed, and$next_futurebecomes cancelled. - When
$futureis fulfilled and$on_fulfilledisundef,$next_futureis fulfilled with the same values as$future. - When
$futureis rejected and$on_rejectedisundef,$next_futureis rejected with the same values as$future. - When
$futureis fulfilled and$on_fulfilledis provided,$on_fulfilledis executed. In this case$next_futurerepresents the result of the$on_fulfilledcallback (see below π).
@returned_values = $on_fulfilled->(@values)
- When
$futureis rejected and$on_rejectedis provided,$on_rejectedis executed. In this case$next_futurerepresents the result of the$on_rejectedcallback (see below π).
@returned_values = $on_rejected->($exception, @detail)
- In the above two cases where the
$on_fulfilledor$on_rejectedcallback is executed, these rules apply to$next_future:- If the callback returns a single
Future(let's call it$returned_future),$next_future's state is synchronized with that of$returned_future. - If the callback throws an exception,
$next_futureis rejected with that exception. The exception is never rethrown to the upper stacks. we keep it contained, periodt β - Otherwise,
$next_futureis fulfilled with the values returned by the callback.
- If the callback returns a single
β οΈ Note that the whole operation can be executed immediately. Like, for example, if$futureis already fulfilled, the$on_fulfilledcallback is executed before$next_futureis returned. And if the$on_fulfilledcallback does not return a pendingFuture,$next_futureis already in a non-pending state. it just moved that fast π₯
You can call cancel() on $next_future. If $future is pending, it gets cancelled when $next_future is cancelled. And if either $on_fulfilled or $on_rejected is executed and its $returned_future is pending, that $returned_future is cancelled when $next_future is cancelled. the cancellation energy travels, iykyk π
π You should not callfulfill(),reject(),resolve()etc on$next_future. don't do it. not your moment to shine.
Because the then() method passes the $future's failure to the $on_rejected callback or to $next_future, the $future's failure becomes "handled" β meaning Future::Q won't warn you if $future is rejected and DESTROYed. considerate king π
π $next_future = $future->catch([$on_rejected])
It's an alias of $future->then(undef, $on_rejected). that's it, that's the method π
β οΈ Note: The superclassFuturehas its owncatchmethod since version0.33.Future'scatchmethod is different fromFuture::Q's, andFuture::Qoverrides it. so if you're coming from the base class expecting the old behaviour... bestie, adjust πΈ
π§ $next_future = $future->finally($callback)
Registers a callback function that's executed when $future is either fulfilled or rejected. This callback is analogous to the finally block of try-catch-finally statements found in Java etc. you know the one π
It returns a new Future::Q object ($next_future) that keeps the result of the operation.
The mandatory argument, $callback, is a subroutine reference. It gets executed with no arguments when $future is either fulfilled or rejected.
@returned_values = $callback->()
If $callback finishes successfully, $next_future has the same state and values as $future. So like, if $future is fulfilled, $next_future becomes fulfilled with the same values, and if $future is rejected, $next_future becomes rejected with the same failure. In this case the return values of $callback are discarded. thrown away. not invited to the party ποΈ
If $callback fails, $next_future is rejected with the failure thrown by $callback. In this case the values of $future are discarded.
In detail, the state of $next_future is determined by these rules π
- When
$futureis pending,$next_futureis pending. - When
$futureis cancelled,$callbackis not executed, and$next_futurebecomes cancelled. - When
$futureis fulfilled or rejected,$callbackis executed with no arguments.$next_future's state depends on the result of$callback. - If the
$callbackreturns a singleFuture(call it$returned_future),$next_futurewaits for$returned_futureto become non-pending.- When
$returned_futureis pending,$next_futureis pending. - When
$returned_futureis fulfilled or cancelled,$next_futurehas the same state and values as$future. In this case, the values of$returned_futureare discarded. - When
$returned_futureis rejected,$next_futureis rejected with$returned_future's failure.
- When
- If the
$callbackthrows an exception,$next_futureis rejected with that exception. The exception is never rethrown to the upper stacks. same rule as before, no snitching β - Otherwise,
$next_futurehas the same state and values as$future. Values returned from$callbackare discarded.
You can call cancel() on $next_future. If $future is pending, it's cancelled when $next_future is cancelled. And if $callback returns a single Future and that $returned_future is pending, the $returned_future is cancelled when $next_future is cancelled. π
π You should not callfulfill(),reject(),resolve()etc on$next_future. same warning, still true, still serious.
Because the finally() method passes the $future's failure to $next_future, the $future's failure becomes "handled" β so Future::Q won't warn you if $future is rejected and DESTROYed. π
β $future = $future->fulfill(@result)
Fulfills the pending $future with the values @result. slay, you did it π
This method is an alias of $future->done(@result).
π₯ $future = $future->reject($exception, @details)
Rejects the pending $future with the $exception and optional @details. $exception must be a scalar evaluated as boolean true. no empty strings, no zeros, they don't count bestie.
This method is an alias of the fail() method (not the die() method). important distinction, don't mix them up π
π $future = $future->resolve(@result)
Basically the same as the fulfill() method, but if you call it with a single Future object as the argument, $future will follow the given Future's state. it's giving follower energy, and honestly? iconic π
Suppose you call $future->resolve($base_future). Then:
- If
$base_futureis pending,$futureis pending. When$base_futurechanges its state,$futurechanges its state to$base_future's state with the same values. - If
$base_futureis fulfilled,$futureis immediately fulfilled with the same values as$base_future's. - If
$base_futureis rejected,$futureis immediately rejected with the same values as$base_future's. - If
$base_futureis cancelled,$futureis immediately cancelled.
β οΈ After callingresolve(), you should not callfulfill(),reject(),resolve()etc on the$futureanymore. the decision has been made, move on π
You can call cancel() on $future afterwards. If you call $future->cancel(), $base_future is cancelled too. mutual cancellation, we love a supportive duo π«Ά
Because $base_future's state is passed to $future, $base_future's failure becomes "handled" β so Future::Q won't warn you when $base_future is rejected and DESTROYed.
π¦ $is_pending = $future->is_pending()
Returns true if the $future is pending. It returns false otherwise. simple as that π
πΈ $is_fulfilled = $future->is_fulfilled()
Returns true if the $future is fulfilled. It returns false otherwise.
π $is_rejected = $future->is_rejected()
Returns true if the $future is rejected. It returns false otherwise.
π $is_cancelled = $future->is_cancelled()
Returns true if the $future is cancelled. It returns false otherwise. This method is inherited from Future. yes, borrowed from the parent, and it wears it well π
π EXAMPLE π
π« try() and then()
use Future::Q;
## Values returned from try() callback are transformed into a
## fulfilled Future::Q
Future::Q->try(sub {
return (1,2,3);
})->then(sub {
print join(",", @_), "\n"; ## -> 1,2,3
});
## Exception thrown from try() callback is transformed into a
## rejected Future::Q
Future::Q->try(sub {
die "oops!";
})->catch(sub {
my $e = shift;
print $e; ## -> oops! at eg/try.pl line XX.
});
## A Future returned from try() callback is returned as is.
my $f = Future::Q->new;
Future::Q->try(sub {
return $f;
})->then(sub {
print "This is not executed.";
}, sub {
print join(",", @_), "\n"; ## -> a,b,c
});
$f->reject("a", "b", "c");
π§ finally()
use Future::Q;
my $handle;
## Suppose Some::Resource->open() returns a handle to a resource (like
## database) wrapped in a Future
Some::Resource->open()->then(sub {
$handle = shift;
return $handle->read_data(); ## Read data asynchronously
})->then(sub {
my $data = shift;
print "Got data: $data\n";
})->finally(sub {
## Ensure closing the resource handle. This callback is called
## even when open() or read_data() fails.
$handle->close() if $handle;
});
okay that example is genuinely so satisfying β the finally() block is literally the cleanup bestie who shows up no matter what happened at the party π§Ήβ¨ and notice how $handle->close() only runs if $handle, because sometimes open() itself failed and there's nothing to close. guards you against a whole mess of undef pain, no cap.
π DIFFERENCE FROM Q π
Okay bestie, so Future::Q is out here trying to emulate the behavior of the Q module for JavaScript as much as possible, but there are definitely differences in some respects. No cap.
Future::Qhas both roles of"promise"and"deferred"inQ. Currently there is no read-only future like"promise".Future::Qhas the fourth state"cancelled", while promise inQdoes not.- In
Future::Q, callbacks forthen()andtry()methods can be executed immediately, while they are always deferred inQ. This is becauseFuture::Qdoes not assume any event loop mechanism. - In
Future::Q, you must pass a truthy value toreject()method. This is required by the originalFutureclass.
π Missing Methods and Features π
Some methods and features in the Q module are missing in Future::Q. Some of them worth noting are listed below.
promise.fail()βFuturealready has afail()method for a completely different meaning. Usecatch()method instead.promise.progress(),deferred.notify()β Progress handlers are not supported in this version ofFuture::Q.promise.done()βFuturealready has adone()method for a completely different meaning.Future::Qdoesn't need the equivalent ofQ'sdone()method because rejected and unhandled futures are detected in theirDESTROY()method. See also "Reporting Unhandled Failures".promise.fcall()(object method) β Its class method form is enough to get the job done. UseFuture::Q->fcall().promise.all(),promise.allResolve(),promise.allSettled()β UseFuture::Q->needs_all()andFuture::Q->wait_all()methods inherited from the originalFutureclass.promise.inspect()β Use predicate methodsis_pending(),is_fulfilled(),is_rejected()andis_cancelled(). To obtain values from a fulfilled Future, useget()method. To obtain the reason of the failure from a rejected Future, usefailure()method.Q()β UseFuture::Q->wrap()method inherited from the originalFutureclass.Q.onerrorβ Use$OnErrorpackage variable, although it is not exactly the same as"Q.onerror". See also "Reporting Unhandled Failures".
π SEE ALSO π
Qβ<http://documentup.com/kriskowal/q/>β the JavaScript module thatFuture::Qtries to emulate.Promises/A+β<http://promises-aplus.github.io/promises-spec/>β the"Promises/A+"specification for JavaScript promises. This is the spec thatQimplements.Futureβ Base class of this module.Futurehas a lot of methods you may find interesting.Future::Utilsβ Utility functions for Futures. Note that the error handling mechanism ofFuture::Qmay not work well withFuture::Utilsfunctions. Personally I recommend using CPS for looping asynchronous operations.IO::Async::Futureβ Subclass ofFuturethat works well withIO::Asyncevent framework.Promisesβ Another promise/deferred/future/whatever implementation. Its goal is to implementPromises/A+specification. BecauseQis also an implementation ofPromises/A+,PromisesandQ(andFuture::Q) are very similar.AnyEvent::Promisesβ Another port ofQ(implementation ofPromises/A+) in Perl. It depends onAnyEvent.AnyEvent::Promiseβ A simple Promise used withAnyEventcondition variables. Apparently it has nothing to do withPromises/A+.
[AnyEvent::Promise]
[Future] -\
+-- [Future::Q]
[Promises/A+] -- [Q] -/
-- [Promises]
-- [AnyEvent::Promises]
π«Ά BUGS AND FEATURE REQUESTS π«Ά
Please report bugs and feature requests to my Github issues <https://github.com/debug-ito/Future-Q/issues>.
πΈ ACKNOWLEDGEMENT πΈ
Paul Evans, "<leonerd at leonerd.org.uk>" β author of Future.
π AUTHOR π
Toshio Ito, "<toshioito at cpan.org>".
π LICENSE AND COPYRIGHT π
Copyright 2013 Toshio Ito.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
Source/version: perl v5.42.2 Β· date: 2026-02-15 β bye bestie, go slay those futures! πβ¨π¦
π¦ where this page comes from
- alpine 3.24: perl-future-q-doc 0.120-r1 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms