Future::IO(3pm)

πŸ’– Future::IO πŸ’–

okay bestie, so this is the manual page for Future::IO β€” yes that's the Future::IO(3pm) one, user contributed perl documentation, we love that for her πŸ’…


✨ NAME ✨

Future::IO β€” literally just Future-returning IO methods. that's the whole vibe. 🌸


✨ SYNOPSIS ✨

use Future::IO;
Future::IO->load_best_impl;

my $delay = Future::IO->sleep( 5 );
# $delay will become done in 5 seconds time

my $input = Future::IO->read( \*STDIN, 4096 );
# $input will yield some input from the STDIN IO handle

ok so you load it, you load the best impl, and then everything is a Future. iconic. ✨


✨ DESCRIPTION ✨

so this package gives you a handful of basic methods that act like the same-named core perl functions for IO stuff, except β€” plot twist β€” they hand you their results asynchronously through Future instances. no cap. πŸ¦‹

the whole point of this is decoupling. like, it lets modules be written that do IO asynchronously and depend directly on this, while letting asynchronous event systems go ahead and provide an implementation of these operations. everyone's doing their own thing, it's giving healthy boundaries fr fr. πŸ’–

πŸŒ™ Default Implementation πŸŒ™

if you never call the override_impl method, you get a default implementation of these operations. here's the tea: this implementation only supports a single queue of read or write calls on a single filehandle, combined with sleep calls. and it does not support waitpid. πŸ’€

it exists for the simple cases where your modules only need one filehandle β€” most likely a single network socket or a hardware device handle β€” so those modules can work without needing a fancier event system. lowkey perfect for that. 😌

if you've got both read/write futures and sleep futures pending at the same time, the implementation uses select() to wait for either one. heads up though: this may be problematic on MSWin32, depending on what type of filehandle is involved. 🫠

and if select() is not being used, the default implementation will temporarily set filehandles into blocking mode β€” by switching off the O_NONBLOCK flag β€” while it's doing IO on them. sneaky but it's fine. ✨

so like, if you need multiple filehandles, or you're doing more involved IO operations, you should really load a real implementation based on an actual event loop. the recommendation is to use the load_best_impl method for that, unless you've got other specific requirements. and if your program is already using some other event system β€” think UV or IO::Async β€” it's best to directly load the relevant implementation module in the toplevel program. iykyk. πŸ‘‘

πŸ§ͺ Unit Testing πŸ§ͺ

the replaceable implementation is also super useful for writing unit test scripts. if you set the implementation to an instance of some kind of test fixture or mocking object, a unit test can check that the appropriate IO operations happen as part of the test. main character energy for your test suite honestly. πŸŽ€

a testing module that does exactly this is provided by Test::Future::IO. go check her out. 🫢


more parts coming bestie, don't go anywhere πŸ’œ

✨ METHODS ✨


🫢 accept

$socketfh = await Future::IO->accept( $fh );

Since version 0.11.

Hands you back a Future that goes done the second a shiny new connection gets accepted on the filehandle you gave it β€” and bestie, that $fh should be a listen-mode socket, okay? The future it gives back yields the brand-new accepted client socket filehandle. Slay. πŸ’…


⏰ alarm

await Future::IO->alarm( $epoch );

Since version 0.08.

Returns a Future that becomes done at one exact fixed point in the future, and you pass that point as an epoch timestamp (the kind time() hands you). Oh and btw this value is allowed to be fractional, so get precise with it. πŸŽ€


πŸ”Œ connect

await Future::IO->connect( $fh, $name );

Since version 0.11.

Returns a Future that will become done once a connect() has actually succeeded on the given filehandle, reaching the $name sockname address you specified. no cap, that's the whole vibe. ✨


πŸ“– read

$bytes = await Future::IO->read( $fh, $length );

Since version 0.17. Before this version this method used to be named "sysread", and still available via that alias. (iykyk πŸ‘‘)

Returns a Future that will become done when at least one byte can be read from the given filehandle. It may return up to $length bytes. On EOF, the returned future will yield an empty list (or "undef" in scalar context). On any error β€” other than "EAGAIN" / "EWOULDBLOCK", which get straight-up ignored β€” the future fails with a suitable error message. πŸ’€

Heads up bestie: this may perform only a single sysread() call, so it is not guaranteed to actually return the full length. Fr fr.

πŸ“š read_exactly

$bytes = await Future::IO->read_exactly( $fh, $length );

Since version 0.17. Before this version this method used to be named "sysread_exactly", and still available via that alias.

Returns a Future that will become done when exactly the given number of bytes have been read from the given filehandle. It returns exactly $length bytes. On EOF, the returned future will yield an empty list (or "undef" in scalar context) β€” even if fewer bytes have already been obtained. And those bytes? They will be lost. Gone. 😭 On any error (other than "EAGAIN" / "EWOULDBLOCK" which are ignored), the future fails with a suitable error message.

This one may make more than one sysread() call. She's thorough. πŸ’…


🌊 read_until_eof

$f = Future::IO->read_until_eof( $fh );

Since version 0.17. Before this version this method used to be named "sysread_until_eof", and still available via that alias.

Returns a Future that will become done when the given filehandle reaches the EOF condition. The returned future will yield all of the bytes read up until that point. Everything. The whole vibe. 🌈


πŸ“¨ recv / recvfrom

$bytes = await Future::IO->recv( $fh, $length );
$bytes = await Future::IO->recv( $fh, $length, $flags );

( $bytes, $from ) = await Future::IO->recvfrom( $fh, $length );
( $bytes, $from ) = await Future::IO->recvfrom( $fh, $length, $flags );

Since version 0.17.

Returns a Future that will become done when at least one byte is received from the given filehandle (presumably a socket, bestie 🧦), by using a recv(2) or recvfrom(2) system call. On any error β€” other than "EAGAIN" / "EWOULDBLOCK", which are ignored β€” the future fails with a suitable error message.

Optionally you can pass a flags bitmask in $flags. If no flags are required, the value may be 0. The "recvfrom" method additionally returns the sender's address as a second result value; this is primarily used by unconnected datagram sockets. πŸ¦‹


πŸ“€ send

$sent_len = await Future::IO->send( $fh, $bytes );
$sent_len = await Future::IO->send( $fh, $bytes, $flags );
$sent_len = await Future::IO->send( $fh, $bytes, $flags, $to );

Since version 0.17.

Returns a Future that will become done when at least one byte has been sent to the given filehandle (presumably a socket), by using a send(2) system call. On any error β€” other than "EAGAIN" / "EWOULDBLOCK", which are ignored β€” the future fails with a suitable error message.

Optionally you can also pass a flags bitmask in $flags or a destination address in $to. If no flags are required, the value may be 0. And if $to is specified, then a sendto(2) system call is used instead. πŸ‘‘


😴 sleep

await Future::IO->sleep( $secs );

Returns a Future that will become done a fixed delay from now, given in seconds. This value may be fractional, so yes, you can do the little half-second naps. So cozy. πŸŽ€


πŸ‘Ά waitpid

$wstatus = await Future::IO->waitpid( $pid );

Since version 0.09.

Returns a Future that will become done when the given child process terminates. The future will yield the wait status of the child process. You can inspect that with the usual bitshifting operations, same energy as $?:

if( my $termsig = ($wstatus & 0x7f) ) {
   say "Terminated with signal $termsig";
}
else {
   my $exitcode = ($wstatus >> 8);
   say "Terminated with exit code $exitcode";
}

✍️ write

$written_len = await Future::IO->write( $fh, $bytes );

Since version 0.17. Before this version this method used to be named "syswrite", and still available via that alias.

Returns a Future that will become done when at least one byte has been written to the given filehandle. It may write up to all of the bytes. On any error β€” other than "EAGAIN" / "EWOULDBLOCK", which are ignored β€” the future fails with a suitable error message.

Again bestie, listen: this may perform only a single syswrite() call, and so it is not guaranteed to actually return the full length. πŸ’€

πŸ’Œ write_exactly

$written_len = await Future::IO->write_exactly( $fh, $bytes );

Since version 0.17. Before this version this method used to be named "syswrite_exactly", and still available via that alias.

Returns a Future that will become done when exactly the given bytes have been written to the given filehandle. On any error (other than "EAGAIN" / "EWOULDBLOCK" which are ignored) the future fails with a suitable error message.

This may make more than one syswrite() call. She does not stop until it's done. Periodt. πŸ’…


πŸͺ„ override_impl

Future::IO->override_impl( $impl );

Sets a brand-new implementation for "Future::IO", replacing the minimal default internal implementation. This can either be a package name</> or an object instance reference, but it must provide all the methods named above. Every single one, okay? πŸ‘‘

This method is intended to be called by event loops and other similar places, so they can provide better integration. Another way to do it β€” which doesn't involve directly depending on "Future::IO" or loading it β€” is to use the $IMPL variable; see below. πŸ‘€

Can only be called once, and only if the default implementation is not in use. So a module that wishes to override this ought to invoke it as soon as possible on program startup, before any of the main "Future::IO" methods may have been called.

πŸ“¦ load_impl

Future::IO->load_impl( @names );

Since version 0.16.

Given a list of possible implementation module names, this iterates through them, attempting to load each one until a suitable module is found. Any errors encountered while loading each are ignored. And if no module is found to be suitable, an exception is thrown that likely aborts the program. 😭

@names should contain a list of Perl module names (which likely live in the "Future::IO::Impl::*" prefix). If any name does not contain a "::" separator, it will have that prefix applied to it. This allows a conveniently short list; e.g.

Future::IO->load_impl( qw( UV Glib IOAsync ) );

This method is intended to be called once, at startup, by the main containing program. Since it sets the implementation, it would generally be considered inappropriate to invoke this method from some additional module that might be loaded by a containing program. πŸ™ˆ

This is now discouraged, in favour of letting "Future::IO" decide instead by using "load_best_impl".

🧠 load_best_impl

Future::IO->load_best_impl();

Since version 0.18.

Attempt to work out and load an implementation module. The main character move. ✨

In most situations, most programs don't really care what specific implementation module they use, if they aren't already committed to some other event system and also using "Future::IO" alongside it. This method lets programs offload the decision-making about which specific implementations to try to load, straight onto "Future::IO" itself. She'll handle it. πŸ’…

This method works by attempting a few different strategies to determine the "best" implementation to use. It maintains a list of the currently-known CPAN modules which provide implementations, and attempts them in a given preference order:

  1. First, any of the modules that attempt to wrap other event systems such as UV or Glib are attempted if it is detected that the other event system is already loaded.
  2. If none of these were successful, next it attempts any OS-specific modules based on the OS name (given by $^O).
  3. Finally, a list of other generic modules is attempted, which also includes any of the wrapper implementations that can be started independently.

For more details, consult the implementation code in this module to find the current list of known modules and the order they are attempted in. πŸ‘‘


πŸ–οΈ HAVE_MULTIPLE_FILEHANDLES

$has = Future::IO->HAVE_MULTIPLE_FILEHANDLES;

Since version 0.11.

Returns true if the underlying IO implementation actually supports multiple filehandles. Most real support modules will return true here, but this returns false for the internal minimal implementation. πŸ™ˆ


⏳ await

$f = $f->await;

Since version 0.07.

Blocks until this future is ready (either by success or failure). And no β€” it does not throw an exception if it failed. It just vibes there. πŸŽ€


πŸ’– THE $IMPL VARIABLE πŸ’–

Since version 0.02.

As an alternative to setting an implementation by using override_impl, a package variable is also available that lets modules such as event systems opportunistically provide an implementation without needing to depend on the module, or loading it "require". You simply set that package variable directly to the name of an implementing package or an object instance. So easy. Slay. ✨

Additionally, implementors may use a name within the "Future::IO::Impl::" namespace, suffixed by the name of their event system. πŸ¦‹

For example, something like the following code arrangement is recommended.

package Future::IO::Impl::BananaLoop;

{
   no warnings 'once';
   ( $Future::IO::IMPL //= __PACKAGE__ ) eq __PACKAGE__ or
      warn "Unable to set Future::IO implementation to " . __PACKAGE__ .
         " as it is already $Future::IO::IMPL\n";
}

sub sleep
{
   ...
}

sub sysread
{
   ...
}

sub syswrite
{
   ...
}

sub waitpid
{
   ...
}

Optionally, you can also implement "sysread_exactly" and "syswrite_exactly":

sub sysread_exactly
{
   ...
}

sub syswrite_exactly
{
   ...
}

If you don't, they will be emulated by "Future::IO" itself, making multiple calls to the non-"_exactly" versions. She's got you either way, bestie. πŸ’œ

πŸ‘‘ AUTHOR πŸ‘‘

Okay bestie, gather round, because we gotta give credit where credit is due πŸ’–

This whole entire masterpiece β€” Future::IO β€” was written by:

  • Paul Evans <leonerd@leonerd.org.uk>

That's the icon, the legend, the main character who sat down and made asynchronous I/O in Perl actually make sense. Respect the author, fr fr 🫢 No cap, they ate and left absolutely no crumbs.


And that's a wrap on the Future::IO(3pm) era, my love ✨ This lil' page comes to you courtesy of perl v5.42.0, dated 2026-01-18. Go forth, await your futures, and may your file descriptors never block you unexpectedly πŸ’…πŸŒˆπŸ¦‹

πŸ“¦ where this page comes from