summaryrefslogtreecommitdiff
path: root/README
diff options
context:
space:
mode:
Diffstat (limited to 'README')
-rw-r--r--README945
1 files changed, 945 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..9f193f0
--- /dev/null
+++ b/README
@@ -0,0 +1,945 @@
+NAME
+ `Future' - represent an operation awaiting completion
+
+SYNOPSIS
+ my $future = Future->new;
+
+ perform_some_operation(
+ on_complete => sub {
+ $future->done( @_ );
+ }
+ );
+
+ $future->on_ready( sub {
+ say "The operation is complete";
+ } );
+
+DESCRIPTION
+ A `Future' object represents an operation that is currently in progress,
+ or has recently completed. It can be used in a variety of ways to manage
+ the flow of control, and data, through an asynchronous program.
+
+ Some futures represent a single operation and are explicitly marked as
+ ready by calling the `done' or `fail' methods. These are called "leaf"
+ futures here, and are returned by the `new' constructor.
+
+ Other futures represent a collection of sub-tasks, and are implicitly
+ marked as ready depending on the readiness of their component futures as
+ required. These are called "convergent" futures here as they converge
+ control and data-flow back into one place. These are the ones returned
+ by the various `wait_*' and `need_*' constructors.
+
+ It is intended that library functions that perform asynchronous
+ operations would use future objects to represent outstanding operations,
+ and allow their calling programs to control or wait for these operations
+ to complete. The implementation and the user of such an interface would
+ typically make use of different methods on the class. The methods below
+ are documented in two sections; those of interest to each side of the
+ interface.
+
+ It should be noted however, that this module does not in any way provide
+ an actual mechanism for performing this asynchronous activity; it merely
+ provides a way to create objects that can be used for control and data
+ flow around those operations. It allows such code to be written in a
+ neater, forward-reading manner, and simplifies many common patterns that
+ are often involved in such situations.
+
+ See also Future::Utils which contains useful loop-constructing
+ functions, to run a future-returning function repeatedly in a loop.
+
+ SUBCLASSING
+ This class easily supports being subclassed to provide extra behavior,
+ such as giving the `get' method the ability to block and wait for
+ completion. This may be useful to provide `Future' subclasses with event
+ systems, or similar.
+
+ Each method that returns a new future object will use the invocant to
+ construct its return value. If the constructor needs to perform
+ per-instance setup it can override the `new' method, and take context
+ from the given instance.
+
+ sub new
+ {
+ my $proto = shift;
+ my $self = $proto->SUPER::new;
+
+ if( ref $proto ) {
+ # Prototype was an instance
+ }
+ else {
+ # Prototype was a class
+ }
+
+ return $self;
+ }
+
+ If an instance provides a method called `await', this will be called by
+ the `get' and `failure' methods if the instance is pending.
+
+ $f->await
+
+ In most cases this should allow future-returning modules to be used as
+ if they were blocking call/return-style modules, by simply appending a
+ `get' call to the function or method calls.
+
+ my ( $results, $here ) = future_returning_function( @args )->get;
+
+ The examples directory in the distribution contains some examples of how
+ futures might be integrated with various event systems.
+
+ MODULE DOCUMENTATION
+ Modules that provide future-returning functions or methods may wish to
+ adopt the following styles in some way, to document the eventual return
+ values from these futures.
+
+ func( ARGS, HERE... ) ==> ( RETURN, VALUES... )
+
+ OBJ->method( ARGS, HERE... ) ==> ( RETURN, VALUES... )
+
+ Code returning a future that yields no values on success can use empty
+ parentheses.
+
+ func( ... ) ==> ()
+
+ DEBUGGING
+ By the time a `Future' object is destroyed, it ought to have been
+ completed or cancelled. By enabling debug tracing of objects, this fact
+ can be checked. If a future object is destroyed without having been
+ completed or cancelled, a warning message is printed.
+
+ $ PERL_FUTURE_DEBUG=1 perl -MFuture -E 'my $f = Future->new'
+ Future=HASH(0xaa61f8) was constructed at -e line 1 and was lost near -e line 0 before it was ready.
+
+ Note that due to a limitation of perl's `caller' function within a
+ `DESTROY' destructor method, the exact location of the leak cannot be
+ accurately determined. Often the leak will occur due to falling out of
+ scope by returning from a function; in this case the leak location may
+ be reported as being the line following the line calling that function.
+
+ $ PERL_FUTURE_DEBUG=1 perl -MFuture
+ sub foo {
+ my $f = Future->new;
+ }
+
+ foo();
+ print "Finished\n";
+
+ Future=HASH(0x14a2220) was constructed at - line 2 and was lost near - line 6 before it was ready.
+ Finished
+
+ A warning is also printed in debug mode if a `Future' object is
+ destroyed that completed with a failure, but the object believes that
+ failure has not been reported anywhere.
+
+ $ PERL_FUTURE_DEBUG=1 perl -Mblib -MFuture -E 'my $f = Future->fail("Oops")'
+ Future=HASH(0xac98f8) was constructed at -e line 1 and was lost near -e line 0 with an unreported failure of: Oops
+
+ Such a failure is considered reported if the `get' or `failure' methods
+ are called on it, or it had at least one `on_ready' or `on_fail'
+ callback, or its failure is propagated to another `Future' instance (by
+ a sequencing or converging method).
+
+CONSTRUCTORS
+ $future = Future->new
+ $future = $orig->new
+ Returns a new `Future' instance to represent a leaf future. It will be
+ marked as ready by any of the `done', `fail', or `cancel' methods. It
+ can be called either as a class method, or as an instance method. Called
+ on an instance it will construct another in the same class, and is
+ useful for subclassing.
+
+ This constructor would primarily be used by implementations of
+ asynchronous interfaces.
+
+ $future = Future->done( @values )
+ $future = Future->fail( $exception, @details )
+ Shortcut wrappers around creating a new `Future' then immediately
+ marking it as done or failed.
+
+ $future = Future->wrap( @values )
+ If given a single argument which is already a `Future' reference, this
+ will be returned unmodified. Otherwise, returns a new `Future' instance
+ that is already complete, and will yield the given values.
+
+ This will ensure that an incoming argument is definitely a `Future', and
+ may be useful in such cases as adapting synchronous code to fit
+ asynchronous libraries driven by `Future'.
+
+ $future = Future->call( \&code, @args )
+ A convenient wrapper for calling a `CODE' reference that is expected to
+ return a future. In normal circumstances is equivalent to
+
+ $future = $code->( @args )
+
+ except that if the code throws an exception, it is wrapped in a new
+ immediate fail future. If the return value from the code is not a
+ blessed `Future' reference, an immediate fail future is returned instead
+ to complain about this fact.
+
+IMPLEMENTATION METHODS
+ These methods would primarily be used by implementations of asynchronous
+ interfaces.
+
+ $future->done( @result )
+ Marks that the leaf future is now ready, and provides a list of values
+ as a result. (The empty list is allowed, and still indicates the future
+ as ready). Cannot be called on a convergent future.
+
+ If the future is already cancelled, this request is ignored. If the
+ future is already complete with a result or a failure, an exception is
+ thrown.
+
+ Future->done( @result )
+ May also be called as a class method, where it will construct a new
+ Future and immediately mark it as done.
+
+ Returns the `$future' to allow easy chaining to create an immediate
+ future by
+
+ return Future->done( ... )
+
+ $code = $future->done_cb
+ Returns a `CODE' reference that, when invoked, calls the `done' method.
+ This makes it simple to pass as a callback function to other code.
+
+ As the same effect can be achieved using curry, this method is
+ deprecated now and may be removed in a later version.
+
+ $code = $future->curry::done;
+
+ $future->fail( $exception, @details )
+ Marks that the leaf future has failed, and provides an exception value.
+ This exception will be thrown by the `get' method if called.
+
+ The exception must evaluate as a true value; false exceptions are not
+ allowed. Further details may be provided that will be returned by the
+ `failure' method in list context. These details will not be part of the
+ exception string raised by `get'.
+
+ If the future is already cancelled, this request is ignored. If the
+ future is already complete with a result or a failure, an exception is
+ thrown.
+
+ Future->fail( $exception, @details )
+ May also be called as a class method, where it will construct a new
+ Future and immediately mark it as failed.
+
+ Returns the `$future' to allow easy chaining to create an immediate
+ failed future by
+
+ return Future->fail( ... )
+
+ $code = $future->fail_cb
+ Returns a `CODE' reference that, when invoked, calls the `fail' method.
+ This makes it simple to pass as a callback function to other code.
+
+ As the same effect can be achieved using curry, this method is
+ deprecated now and may be removed in a later version.
+
+ $code = $future->curry::fail;
+
+ $future->die( $message, @details )
+ A convenient wrapper around `fail'. If the exception is a non-reference
+ that does not end in a linefeed, its value will be extended by the file
+ and line number of the caller, similar to the logic that `die' uses.
+
+ Returns the `$future'.
+
+ $future->on_cancel( $code )
+ If the future is not yet ready, adds a callback to be invoked if the
+ future is cancelled by the `cancel' method. If the future is already
+ ready, throws an exception.
+
+ If the future is cancelled, the callbacks will be invoked in the reverse
+ order to that in which they were registered.
+
+ $on_cancel->( $future )
+
+ $future->on_cancel( $f )
+ If passed another `Future' instance, the passed instance will be
+ cancelled when the original future is cancelled. This method does
+ nothing if the future is already complete.
+
+ $cancelled = $future->is_cancelled
+ Returns true if the future has been cancelled by `cancel'.
+
+USER METHODS
+ These methods would primarily be used by users of asynchronous
+ interfaces, on objects returned by such an interface.
+
+ $ready = $future->is_ready
+ Returns true on a leaf future if a result has been provided to the
+ `done' method, failed using the `fail' method, or cancelled using the
+ `cancel' method.
+
+ Returns true on a convergent future if it is ready to yield a result,
+ depending on its component futures.
+
+ $future->on_ready( $code )
+ If the future is not yet ready, adds a callback to be invoked when the
+ future is ready. If the future is already ready, invokes it immediately.
+
+ In either case, the callback will be passed the future object itself.
+ The invoked code can then obtain the list of results by calling the
+ `get' method.
+
+ $on_ready->( $future )
+
+ Returns the `$future'.
+
+ $future->on_ready( $f )
+ If passed another `Future' instance, the passed instance will have its
+ `done', `fail' or `cancel' methods invoked when the original future
+ completes successfully, fails, or is cancelled respectively.
+
+ $done = $future->is_done
+ Returns true on a future if it is ready and completed successfully.
+ Returns false if it is still pending, failed, or was cancelled.
+
+ @result = $future->get
+ $result = $future->get
+ If the future is ready and completed successfully, returns the list of
+ results that had earlier been given to the `done' method on a leaf
+ future, or the list of component futures it was waiting for on a
+ convergent future. In scalar context it returns just the first result
+ value.
+
+ If the future is ready but failed, this method raises as an exception
+ the failure string or object that was given to the `fail' method.
+
+ If the future was cancelled an exception is thrown.
+
+ If it is not yet ready and is not of a subclass that provides an `await'
+ method an exception is thrown. If it is subclassed to provide an `await'
+ method then this is used to wait for the future to be ready, before
+ returning the result or propagating its failure exception.
+
+ @values = Future->unwrap( @values )
+ If given a single argument which is a `Future' reference, this method
+ will call `get' on it and return the result. Otherwise, it returns the
+ list of values directly in list context, or the first value in scalar.
+ Since it involves an implicit `await', this method can only be used on
+ immediate futures or subclasses that implement `await'.
+
+ This will ensure that an outgoing argument is definitely not a `Future',
+ and may be useful in such cases as adapting synchronous code to fit
+ asynchronous libraries that return `Future' instances.
+
+ $future->on_done( $code )
+ If the future is not yet ready, adds a callback to be invoked when the
+ future is ready, if it completes successfully. If the future completed
+ successfully, invokes it immediately. If it failed or was cancelled, it
+ is not invoked at all.
+
+ The callback will be passed the result passed to the `done' method.
+
+ $on_done->( @result )
+
+ Returns the `$future'.
+
+ $future->on_done( $f )
+ If passed another `Future' instance, the passed instance will have its
+ `done' method invoked when the original future completes successfully.
+
+ $failed = $future->is_failed
+ Returns true on a future if it is ready and it failed. Returns false if
+ it is still pending, completed successfully, or was cancelled.
+
+ $exception = $future->failure
+ $exception, @details = $future->failure
+ Returns the exception passed to the `fail' method, `undef' if the future
+ completed successfully via the `done' method, or raises an exception if
+ called on a future that is not yet ready.
+
+ If called in list context, will additionally yield a list of the details
+ provided to the `fail' method.
+
+ Because the exception value must be true, this can be used in a simple
+ `if' statement:
+
+ if( my $exception = $future->failure ) {
+ ...
+ }
+ else {
+ my @result = $future->get;
+ ...
+ }
+
+ $future->on_fail( $code )
+ If the future is not yet ready, adds a callback to be invoked when the
+ future is ready, if it fails. If the future has already failed, invokes
+ it immediately. If it completed successfully or was cancelled, it is not
+ invoked at all.
+
+ The callback will be passed the exception and details passed to the
+ `fail' method.
+
+ $on_fail->( $exception, @details )
+
+ Returns the `$future'.
+
+ $future->on_fail( $f )
+ If passed another `Future' instance, the passed instance will have its
+ `fail' method invoked when the original future fails.
+
+ To invoke a `done' method on a future when another one fails, use a CODE
+ reference:
+
+ $future->on_fail( sub { $f->done( @_ ) } );
+
+ $future->cancel
+ Requests that the future be cancelled, immediately marking it as ready.
+ This will invoke all of the code blocks registered by `on_cancel', in
+ the reverse order. When called on a convergent future, all its component
+ futures are also cancelled. It is not an error to attempt to cancel a
+ future that is already complete or cancelled; it simply has no effect.
+
+ Returns the `$future'.
+
+ $code = $future->cancel_cb
+ Returns a `CODE' reference that, when invoked, calls the `cancel'
+ method. This makes it simple to pass as a callback function to other
+ code.
+
+ As the same effect can be achieved using curry, this method is
+ deprecated now and may be removed in a later version.
+
+ $code = $future->curry::cancel;
+
+SEQUENCING METHODS
+ The following methods all return a new future to represent the
+ combination of its invocant followed by another action given by a code
+ reference. The combined activity waits for the first future to be ready,
+ then may invoke the code depending on the success or failure of the
+ first, or may run it regardless. The returned sequence future represents
+ the entire combination of activity.
+
+ In some cases the code should return a future; in some it should return
+ an immediate result. If a future is returned, the combined future will
+ then wait for the result of this second one. If the combinined future is
+ cancelled, it will cancel either the first future or the second,
+ depending whether the first had completed. If the code block throws an
+ exception instead of returning a value, the sequence future will fail
+ with that exception as its message and no further values.
+
+ As it is always a mistake to call these sequencing methods in void
+ context and lose the reference to the returned future (because
+ exception/error handling would be silently dropped), this method warns
+ in void context.
+
+ $future = $f1->then( \&done_code )
+ Returns a new sequencing `Future' that runs the code if the first
+ succeeds. Once `$f1' succeeds the code reference will be invoked and is
+ passed the list of results. It should return a future, `$f2'. Once `$f2'
+ completes the sequence future will then be marked as complete with
+ whatever result `$f2' gave. If `$f1' fails then the sequence future will
+ immediately fail with the same failure and the code will not be invoked.
+
+ $f2 = $done_code->( @result )
+
+ $future = $f1->else( \&fail_code )
+ Returns a new sequencing `Future' that runs the code if the first fails.
+ Once `$f1' fails the code reference will be invoked and is passed the
+ failure and details. It should return a future, `$f2'. Once `$f2'
+ completes the sequence future will then be marked as complete with
+ whatever result `$f2' gave. If `$f1' succeeds then the sequence future
+ will immediately succeed with the same result and the code will not be
+ invoked.
+
+ $f2 = $fail_code->( $exception, @details )
+
+ $future = $f1->then( \&done_code, \&fail_code )
+ The `then' method can also be passed the `$fail_code' block as well,
+ giving a combination of `then' and `else' behaviour.
+
+ This operation is designed to be compatible with the semantics of other
+ future systems, such as Javascript's Q or Promises/A libraries.
+
+ $future = $f1->transform( %args )
+ Returns a new sequencing `Future' that wraps the one given as `$f1'.
+ With no arguments this will be a trivial wrapper; `$future' will
+ complete or fail when `$f1' does, and `$f1' will be cancelled when
+ `$future' is.
+
+ By passing the following named arguments, the returned `$future' can be
+ made to behave differently to `$f1':
+
+ done => CODE
+ Provides a function to use to modify the result of a successful
+ completion. When `$f1' completes successfully, the result of its
+ `get' method is passed into this function, and whatever it
+ returns is passed to the `done' method of `$future'
+
+ fail => CODE
+ Provides a function to use to modify the result of a failure.
+ When `$f1' fails, the result of its `failure' method is passed
+ into this function, and whatever it returns is passed to the
+ `fail' method of `$future'.
+
+ $future = $f1->then_with_f( \&code )
+ Returns a new sequencing `Future' that runs the code if the first
+ succeeds. Identical to `then', except that the code reference will be
+ passed both the original future, `$f1', and its result.
+
+ $f2 = $code->( $f1, @result )
+
+ This is useful for conditional execution cases where the code block may
+ just return the same result of the original future. In this case it is
+ more efficient to return the original future itself.
+
+ $future = $f->then_done( @result )
+ $future = $f->then_fail( $exception, @details )
+ Convenient shortcuts to returning an immediate future from a `then'
+ block, when the result is already known.
+
+ $future = $f1->else_with_f( \&code )
+ Returns a new sequencing `Future' that runs the code if the first fails.
+ Identical to `else', except that the code reference will be passed both
+ the original future, `$f1', and its exception and details.
+
+ $f2 = $code->( $f1, $exception, @details )
+
+ This is useful for conditional execution cases where the code block may
+ just return the same result of the original future. In this case it is
+ more efficient to return the original future itself.
+
+ $future = $f->else_done( @result )
+ $future = $f->else_fail( $exception, @details )
+ Convenient shortcuts to returning an immediate future from a `else'
+ block, when the result is already known.
+
+ $future = $f1->followed_by( \&code )
+ Returns a new sequencing `Future' that runs the code regardless of
+ success or failure. Once `$f1' is ready the code reference will be
+ invoked and is passed one argument, `$f1'. It should return a future,
+ `$f2'. Once `$f2' completes the sequence future will then be marked as
+ complete with whatever result `$f2' gave.
+
+ $f2 = $code->( $f1 )
+
+ $future = $f1->without_cancel
+ Returns a new sequencing `Future' that will complete with the success or
+ failure of the original future, but if cancelled, will not cancel the
+ original. This may be useful if the original future represents an
+ operation that is being shared among multiple sequences; cancelling one
+ should not prevent the others from running too.
+
+CONVERGENT FUTURES
+ The following constructors all take a list of component futures, and
+ return a new future whose readiness somehow depends on the readiness of
+ those components. The first derived class component future will be used
+ as the prototype for constructing the return value, so it respects
+ subclassing correctly, or failing that a plain `Future'.
+
+ $future = Future->wait_all( @subfutures )
+ Returns a new `Future' instance that will indicate it is ready once all
+ of the sub future objects given to it indicate that they are ready,
+ either by success, failure or cancellation. Its result will a list of
+ its component futures.
+
+ When given an empty list this constructor returns a new immediately-done
+ future.
+
+ This constructor would primarily be used by users of asynchronous
+ interfaces.
+
+ $future = Future->wait_any( @subfutures )
+ Returns a new `Future' instance that will indicate it is ready once any
+ of the sub future objects given to it indicate that they are ready,
+ either by success or failure. Any remaining component futures that are
+ not yet ready will be cancelled. Its result will be the result of the
+ first component future that was ready; either success or failure. Any
+ component futures that are cancelled are ignored, apart from the final
+ component left; at which point the result will be a failure.
+
+ When given an empty list this constructor returns an immediately-failed
+ future.
+
+ This constructor would primarily be used by users of asynchronous
+ interfaces.
+
+ $future = Future->needs_all( @subfutures )
+ Returns a new `Future' instance that will indicate it is ready once all
+ of the sub future objects given to it indicate that they have completed
+ successfully, or when any of them indicates that they have failed. If
+ any sub future fails, then this will fail immediately, and the remaining
+ subs not yet ready will be cancelled. Any component futures that are
+ cancelled will cause an immediate failure of the result.
+
+ If successful, its result will be a concatenated list of the results of
+ all its component futures, in corresponding order. If it fails, its
+ failure will be that of the first component future that failed. To
+ access each component future's results individually, use `done_futures'.
+
+ When given an empty list this constructor returns a new immediately-done
+ future.
+
+ This constructor would primarily be used by users of asynchronous
+ interfaces.
+
+ $future = Future->needs_any( @subfutures )
+ Returns a new `Future' instance that will indicate it is ready once any
+ of the sub future objects given to it indicate that they have completed
+ successfully, or when all of them indicate that they have failed. If any
+ sub future succeeds, then this will succeed immediately, and the
+ remaining subs not yet ready will be cancelled. Any component futures
+ that are cancelled are ignored, apart from the final component left; at
+ which point the result will be a failure.
+
+ If successful, its result will be that of the first component future
+ that succeeded. If it fails, its failure will be that of the last
+ component future to fail. To access the other failures, use
+ `failed_futures'.
+
+ Normally when this future completes successfully, only one of its
+ component futures will be done. If it is constructed with multiple that
+ are already done however, then all of these will be returned from
+ `done_futures'. Users should be careful to still check all the results
+ from `done_futures' in that case.
+
+ When given an empty list this constructor returns an immediately-failed
+ future.
+
+ This constructor would primarily be used by users of asynchronous
+ interfaces.
+
+METHODS ON CONVERGENT FUTURES
+ The following methods apply to convergent (i.e. non-leaf) futures, to
+ access the component futures stored by it.
+
+ @f = $future->pending_futures
+ @f = $future->ready_futures
+ @f = $future->done_futures
+ @f = $future->failed_futures
+ @f = $future->cancelled_futures
+ Return a list of all the pending, ready, done, failed, or cancelled
+ component futures. In scalar context, each will yield the number of such
+ component futures.
+
+TRACING METHODS
+ $future = $future->set_label( $label )
+ $label = $future->label
+ Chaining mutator and accessor for the label of the `Future'. This should
+ be a plain string value, whose value will be stored by the future
+ instance for use in debugging messages or other tooling, or similar
+ purposes.
+
+ [ $sec, $usec ] = $future->btime
+ [ $sec, $usec ] = $future->rtime
+ Accessors that return the tracing timestamps from the instance. These
+ give the time the instance was contructed ("birth" time, `btime') and
+ the time the result was determined (the "ready" time, `rtime'). Each
+ result is returned as a two-element ARRAY ref, containing the epoch time
+ in seconds and microseconds, as given by `Time::HiRes::gettimeofday'.
+
+ In order for these times to be captured, they have to be enabled by
+ setting `$Future::TIMES' to a true value. This is initialised true at
+ the time the module is loaded if either `PERL_FUTURE_DEBUG' or
+ `PERL_FUTURE_TIMES' are set in the environment.
+
+ $sec = $future->elapsed
+ If both tracing timestamps are defined, returns the number of seconds of
+ elapsed time between them as a floating-point number. If not, returns
+ `undef'.
+
+ $cb = $future->wrap_cb( $operation_name, $cb )
+ *Since version 0.31.*
+
+ *Note: This method is experimental and may be changed or removed in a
+ later version.*
+
+ This method is invoked internally by various methods that are about to
+ save a callback CODE reference supplied by the user, to be invoked
+ later. The default implementation simply returns the callback agument
+ as-is; the method is provided to allow users to provide extra behaviour.
+ This can be done by applying a method modifier of the `around' kind, so
+ in effect add a chain of wrappers. Each wrapper can then perform its own
+ wrapping logic of the callback. `$operation_name' is a string giving the
+ reason for which the callback is being saved; currently one of
+ `on_ready', `on_done', `on_fail' or `sequence'; the latter being used
+ for all the sequence-returning methods.
+
+ This method is intentionally invoked only for CODE references that are
+ being saved on a pending `Future' instance to be invoked at some later
+ point. It does not run for callbacks to be invoked on an
+ already-complete instance. This is for performance reasons, where the
+ intended behaviour is that the wrapper can provide some amount of
+ context save and restore, to return the operating environment for the
+ callback back to what it was at the time it was saved.
+
+ For example, the following wrapper saves the value of a package variable
+ at the time the callback was saved, and restores that value at
+ invocation time later on. This could be useful for preserving context
+ during logging in a Future-based program.
+
+ our $LOGGING_CTX;
+
+ no warnings 'redefine';
+
+ my $orig = Future->can( "wrap_cb" );
+ *Future::wrap_cb = sub {
+ my $cb = $orig->( @_ );
+
+ my $saved_logging_ctx = $LOGGING_CTX;
+
+ return sub {
+ local $LOGGING_CTX = $saved_logging_ctx;
+ $cb->( @_ );
+ };
+ };
+
+ At this point, any code deferred into a `Future' by any of its callbacks
+ will observe the `$LOGGING_CTX' variable as having the value it held at
+ the time the callback was saved, even if it is invoked later on when
+ that value is different.
+
+ Remember when writing such a wrapper, that it still needs to invoke the
+ previous version of the method, so that it plays nicely in combination
+ with others (see the `$orig->( @_ )' part).
+
+EXAMPLES
+ The following examples all demonstrate possible uses of a `Future'
+ object to provide a fictional asynchronous API.
+
+ For more examples, comparing the use of `Future' with regular
+ call/return style Perl code, see also Future::Phrasebook.
+
+ Providing Results
+ By returning a new `Future' object each time the asynchronous function
+ is called, it provides a placeholder for its eventual result, and a way
+ to indicate when it is complete.
+
+ sub foperation
+ {
+ my %args = @_;
+
+ my $future = Future->new;
+
+ do_something_async(
+ foo => $args{foo},
+ on_done => sub { $future->done( @_ ); },
+ );
+
+ return $future;
+ }
+
+ In most cases, the `done' method will simply be invoked with the entire
+ result list as its arguments. In that case, it is simpler to use the
+ `done_cb' wrapper method to create the `CODE' reference.
+
+ my $future = Future->new;
+
+ do_something_async(
+ foo => $args{foo},
+ on_done => $future->done_cb,
+ );
+
+ The caller may then use this future to wait for a result using the
+ `on_ready' method, and obtain the result using `get'.
+
+ my $f = foperation( foo => "something" );
+
+ $f->on_ready( sub {
+ my $f = shift;
+ say "The operation returned: ", $f->get;
+ } );
+
+ Indicating Success or Failure
+ Because the stored exception value of a failed future may not be false,
+ the `failure' method can be used in a conditional statement to detect
+ success or failure.
+
+ my $f = foperation( foo => "something" );
+
+ $f->on_ready( sub {
+ my $f = shift;
+ if( not my $e = $f->failure ) {
+ say "The operation succeeded with: ", $f->get;
+ }
+ else {
+ say "The operation failed with: ", $e;
+ }
+ } );
+
+ By using `not' in the condition, the order of the `if' blocks can be
+ arranged to put the successful case first, similar to a `try'/`catch'
+ block.
+
+ Because the `get' method re-raises the passed exception if the future
+ failed, it can be used to control a `try'/`catch' block directly. (This
+ is sometimes called *Exception Hoisting*).
+
+ use Try::Tiny;
+
+ $f->on_ready( sub {
+ my $f = shift;
+ try {
+ say "The operation succeeded with: ", $f->get;
+ }
+ catch {
+ say "The operation failed with: ", $_;
+ };
+ } );
+
+ Even neater still may be the separate use of the `on_done' and `on_fail'
+ methods.
+
+ $f->on_done( sub {
+ my @result = @_;
+ say "The operation succeeded with: ", @result;
+ } );
+ $f->on_fail( sub {
+ my ( $failure ) = @_;
+ say "The operation failed with: $failure";
+ } );
+
+ Immediate Futures
+ Because the `done' method returns the future object itself, it can be
+ used to generate a `Future' that is immediately ready with a result.
+ This can also be used as a class method.
+
+ my $f = Future->done( $value );
+
+ Similarly, the `fail' and `die' methods can be used to generate a
+ `Future' that is immediately failed.
+
+ my $f = Future->die( "This is never going to work" );
+
+ This could be considered similarly to a `die' call.
+
+ An `eval{}' block can be used to turn a `Future'-returning function that
+ might throw an exception, into a `Future' that would indicate this
+ failure.
+
+ my $f = eval { function() } || Future->fail( $@ );
+
+ This is neater handled by the `call' class method, which wraps the call
+ in an `eval{}' block and tests the result:
+
+ my $f = Future->call( \&function );
+
+ Sequencing
+ The `then' method can be used to create simple chains of dependent
+ tasks, each one executing and returning a `Future' when the previous
+ operation succeeds.
+
+ my $f = do_first()
+ ->then( sub {
+ return do_second();
+ })
+ ->then( sub {
+ return do_third();
+ });
+
+ The result of the `$f' future itself will be the result of the future
+ returned by the final function, if none of them failed. If any of them
+ fails it will fail with the same failure. This can be considered similar
+ to normal exception handling in synchronous code; the first time a
+ function call throws an exception, the subsequent calls are not made.
+
+ Merging Control Flow
+ A `wait_all' future may be used to resynchronise control flow, while
+ waiting for multiple concurrent operations to finish.
+
+ my $f1 = foperation( foo => "something" );
+ my $f2 = foperation( bar => "something else" );
+
+ my $f = Future->wait_all( $f1, $f2 );
+
+ $f->on_ready( sub {
+ say "Operations are ready:";
+ say " foo: ", $f1->get;
+ say " bar: ", $f2->get;
+ } );
+
+ This provides an ability somewhat similar to `CPS::kpar()' or
+ Async::MergePoint.
+
+KNOWN ISSUES
+ Cancellation of Non-Final Sequence Futures
+ The behaviour of future cancellation still has some unanswered questions
+ regarding how to handle the situation where a future is cancelled that
+ has a sequence future constructed from it.
+
+ In particular, it is unclear in each of the following examples what the
+ behaviour of `$f2' should be, were `$f1' to be cancelled:
+
+ $f2 = $f1->then( sub { ... } ); # plus related ->then_with_f, ...
+
+ $f2 = $f1->else( sub { ... } ); # plus related ->else_with_f, ...
+
+ $f2 = $f1->followed_by( sub { ... } );
+
+ In the `then'-style case it is likely that this situation should be
+ treated as if `$f1' had failed, perhaps with some special message. The
+ `else'-style case is more complex, because it may be that the entire
+ operation should still fail, or it may be that the cancellation of `$f1'
+ should again be treated simply as a special kind of failure, and the
+ `else' logic run as normal.
+
+ To be specific; in each case it is unclear what happens if the first
+ future is cancelled, while the second one is still waiting on it. The
+ semantics for "normal" top-down cancellation of `$f2' and how it affects
+ `$f1' are already clear and defined.
+
+ Cancellation of Divergent Flow
+ A further complication of cancellation comes from the case where a given
+ future is reused multiple times for multiple sequences or convergent
+ trees.
+
+ In particular, it is in clear in each of the following examples what the
+ behaviour of `$f2' should be, were `$f1' to be cancelled:
+
+ my $f_initial = Future->new; ...
+ my $f1 = $f_initial->then( ... );
+ my $f2 = $f_initial->then( ... );
+
+ my $f1 = Future->needs_all( $f_initial );
+ my $f2 = Future->needs_all( $f_initial );
+
+ The point of cancellation propagation is to trace backwards through
+ stages of some larger sequence of operations that now no longer need to
+ happen, because the final result is no longer required. But in each of
+ these cases, just because `$f1' has been cancelled, the initial future
+ `$f_initial' is still required because there is another future (`$f2')
+ that will still require its result.
+
+ Initially it would appear that some kind of reference-counting mechanism
+ could solve this question, though that itself is further complicated by
+ the `on_ready' handler and its variants.
+
+ It may simply be that a comprehensive useful set of cancellation
+ semantics can't be universally provided to cover all cases; and that
+ some use-cases at least would require the application logic to give
+ extra information to its `Future' objects on how they should wire up the
+ cancel propagation logic.
+
+ Both of these cancellation issues are still under active design
+ consideration; see the discussion on RT96685 for more information
+ (https://rt.cpan.org/Ticket/Display.html?id=96685).
+
+SEE ALSO
+ * curry - Create automatic curried method call closures for any class
+ or object
+
+ * "The Past, The Present and The Future" - slides from a talk given at
+ the London Perl Workshop, 2012.
+
+ https://docs.google.com/presentation/d/1UkV5oLcTOOXBXPh8foyxko4PR28_
+ zU_aVx6gBms7uoo/edit
+
+ * "Futures advent calendar 2013"
+
+ http://leonerds-code.blogspot.co.uk/2013/12/futures-advent-day-1.htm
+ l
+
+TODO
+ * Consider the ability to pass the constructor an `await' CODEref,
+ instead of needing to use a subclass. This might simplify
+ async/etc.. implementations, and allows the reuse of the idea of
+ subclassing to extend the abilities of `Future' itself - for example
+ to allow a kind of Future that can report incremental progress.
+
+AUTHOR
+ Paul Evans <leonerd@leonerd.org.uk>
+