2013/12/24

Futures advent day 24

Day 24 - Futures compared to Callbacks

It would seem at first glance that futures provide similar benefits to managing control flow by callbacks. However, they provide several advantages in comparison.

When performing a sequence of many operations using callbacks, the ever-increasing nesting nature of the callback functions leads to an ugly indenting pyramid look in the source code.

FIRST_CB( $arg1, sub {
  SECOND_CB( $arg2, sub {
    THIRD_CB( $arg3, sub {
      FINISHED()
    });
  });
});

Because futures are connected together using the return value of a function, not through a value passed into it, they can avoid this mess and remain at a fixed indentation level. This also allows, for example, a new stage to be added between existing stages without upsetting the indentation of the following code; making neater diff output in revision control systems, and giving less chance of a merge conflict when branching.

FIRST_F( $arg1 )->then(sub {
  SECOND_F( $arg2 )
})->then(sub {
  THIRD_F( $arg3 )
})->then(sub {
  FINISHED()
});

Moreover, many other shapes of control flow start to look much more like their synchronous counterparts, precisely because they are linked together using the return values out of the individual units and require no other values to be passed in.

Possibly the most simple example of concurrent control flow is a two-way merge case, where two operations are started concurrently waiting for the result of both before continuing. Using callbacks this would need to be solved by each callback storing its result in a variable they both lexically capture, and checking in each whether both results have been provided.

my $one_result; my $two_result;

ONE_CB( sub {
  $one_result = shift;
  if( defined $two_result ) {
    FINISHED($one_result, $two_result);
  }
});
TWO_CB( sub {
  $two_result = shift;
  if( defined $one_result ) {
    FINISHED($one_result, $two_result);
  }
});

Immediately two issues come to light here. First is the repeated FINISHED code - if that were itself a further chain of operations with callbacks, this would be impossible (or at least very tedious) to repeat twice, and of course gets much worse beyond two concurrent branches. Secondly, we are testing the results for definedness - maybe undef is a perfectly valid result from each function. In that case we'd have to track two further variables to simply remark whether each operation has completed:

my $one_done; my $one_result;
my $two_done; my $two_result;

ONE_CB( sub {
  $one_result = shift;
  $one_done++;
  if( $two_done ) { ... }
});
...

This example of course only handles the success case. Imagine how much more complex the code would be if each function took two code references, one for success and one for failure, and additionally returned some kind of operation ID that would be used to cancel the operation in progress if it was no longer required. This would now need eight lexically captured variables, adding much more boilerplate control-flow noise to the code. Moreover, now there are more variables being shared among code blocks, it creates the possibility that strong reference cycles remain long after the operation has finished, failed, or been cancelled that retain an object in memory long after it was required. It may end up looking something like (and keep in mind this is the most simple case of two concurrent operations and a single "afterwards"):

my $one_done; my $one_result; my $one_failed; my $one_id;
my $two_done; my $two_result; my $two_failed; my $two_id;

my $finished = sub {
  undef $one_id; undef $two_id;
  FINISHED();
};

$one_id = ONE_CB(
  sub { $one_result = shift; $one_done++;
        $finished->() if $two_done; },
  sub { $one_failed++;
        TWO_CANCEL($two_id) if !$two_done; undef $two_id;
        FAILED() },
);
$two_id = TWO_CB(
  sub { $two_result = shift; $two_done++;
        $finished->() if $one_done; },
  sub { $two_failed++;
        ONE_CANCEL($one_id) if !$one_done; undef $one_id;
        FAILED() },
);

By comparison, the Future needs_all constructor neatly wraps up all this implicit behaviour, removing the control- and data-flow noise from the code, and much more concisely expressing its intent.

Future->needs_all(
  ONE_F(), TWO_F(),
)->then(sub {
  my ( $one_result, $two_result ) = @_;
  FINISHED($one_result, $two_result);
})->else(sub {
  FAILED();
})->get;

So, there we have it. In the past 24 posts we have seen how Futures can neatly express all the various kinds of control-flow logic we typically find in a Perl program, and also express the additional shapes of code we find useful when working with asynchronous and concurrent programming. This neatness ultimately comes from the fact that a Future object is a first-class value representing the operation itself, and being first-class comes the ability to combine it with others to produce new first-class values to represent combinations of this operation with others.

Futures allow the control- and data-flow structure of a program to be inherently expressed together, describing the dependency relationships between individual operations. Both successful results and failures are automatically propagated up from the atomic units that create them, through the various layers of logic up towards the topmost level of the program. Actions in progress can be abandoned when no longer required, causing a graceful cancellation of the activity that had been pending up until that time.

Futures change state from pending to complete when they are provided with a result, meaning that when they become ready they already have the results stored in them. This makes for convenient control-flow that coincides with data-flow; ensuring that the result of an operation is passed to the next operation in the sequence at the time it is executed. This convenient pairing of control- and data-flow stands in contrast to the split nature of other kinds of concurrency control, such as callback functions or locks and mutexes, which generally only manage the flow of control and require other techniques like lexical variables shared between multiple closures to provide the data flow. Such sharing of mutable state between domains of concurrency is the source of many kinds of concurrency bug which cannot happen with Futures.

In summary, Futures provide a useful abstraction to build all kinds of program logic on top of, whether it is initially intended to be asynchronous or not. Middle-level library modules especially will benefit from using Futures to express intent and combine actions together, as they will then automatically be able to make use of asynchronous and concurrent abilities of the base layers they are built from, without having to expressly depend on those being present.

<< First | < Prev

2013/12/23

Futures advent day 23

Day 23 - Additional Benefits of Futures

Beyond simply being able replicate regular perl control-flow styles, building program logic on top of Futures has many additional benefits.

The primary benefit is of course the ability to work asynchronously, allowing the concurrency of being able to start multiple operations and wait for them all to succeed. We have seen this with the tree-forming needs_all, needs_any and wait_any constructor methods, and the fmap utility.

my $f = Future->needs_all(
  ONE(), TWO(), THREE(),
);

my ( $one, $two, $three ) = $f->get;
my $f = fmap1 {
  FUNC($_),
} foreach => [ @VALUES ], concurrent => 10;

my @results = $f->get;

Because Futures represent an operation in progress they are an ideal place to provide cancellation logic, allowing the consumer of the would-be result to abandon it and declare it no longer useful. This can be done explicitly by calling the cancel method.

sub PROCESS_REQUEST {
  my ( $req ) = @_;
  my $f = GET_RESULT( $req->PARAMS );

  $f->on_done(sub {
    $req->REPLY( @_ );
  });
  $req->ON_CLIENT_CLOSE(sub {
    $f->cancel;
  });

  return $f;
}

A failed Future provides an analog to a thrown exception, causing an entire chain or tree of operations to be abandoned and propagating back up towards the caller until a suitable error-handling block is found. In addition however, a failed Future can provide a full list of values as well as a single string. This allows error handlers to be much more fine-grained in their ability to distinguish different types of error.

my $f = GET("http://my-site-here.com/")
  ->else_with_f(sub {
    my ( $f, $failure, $op ) = @_;
    # may be           http, $request, $response
    if( $op eq "http" and $_[3]->code == 500 ) {
      say "Server is unavailable";
      return Future->new->done( $HOLDING_PAGE );
    }
    return $f;
  });

Middleware library functions can easily be built on top of basic actions implemented by futures and providing more of their own. When writing and testing sub libraries it becomes a simple matter to use these futures within the unit-tests themselves as a way to mock out responses from lower levels of logic in order to test the library code in isolation. For example, if we wish to unit-test a middleware function that uses an HTTP user agent to fetch a page, parse it, and return the page title we can provide a simple tiny user agent wrapper that just returns a new future, and does nothing else:

my $resp_f; my $url;
sub GET {
  ( $url ) = @_;
  return $resp_f = Future->new;
}
...

Our unit test can then drive the behaviour of that "user agent", as well as testing the function's results:

...
my $f = get_page_title( \&GET, "http://my-site-here.com/" );

isa_ok( $f, "Future" );
is( $url, "http://my-site-here.com/" );
ok( defined $resp_f, 'Response future created' );
is( !$f->is_ready, '$f is not yet ready' );

$resp_f->done( HTTP::Response->new(
  200, "OK", [ Content_type => "text/html" ],
  "<html><head><title>My title</title></head><body /></html>",
));

ok( $f->is_ready, '$f is now ready after HTML response' );
is( scalar $f->get, "My title", '$f->get returns title' );

Because we have a future to represent both sides of the function (its caller and the inner GET function it uses to fetch the page content) we have been able to easily test the function in the middle. The unit test script itself at various times takes on the role either of the outside caller or the inner HTTP user agent, and is able to easily interleave the two to ensure a neat test.

<< First | < Prev | Next >


Edit 2013/12/29: Updated to use else_with_f

2013/12/22

Futures advent day 22

Day 22 - Equivalence of Control Flow

Over the past twenty or so posts we have seen many examples of control-flow structures using Futures to help write possibly-asynchronous, possibly-concurrent code in simple, neat ways which mirror the regular kinds of synchronous control flow that Perl already provides. You may by now have come to the conclusion that it is possible to duplicate any kind of control-flow logic using futures.

Simple sequencing of one operation then the next is done using then:

FIRST();
SECOND();
THIRD();
FIRST()
  ->then(sub { SECOND() })
  ->then(sub { THIRD() });

Sequencing is interrupted by thrown exceptions, which may be caught using else:

try { FIRST();
      SECOND();
} catch {
      CATCH();
};
FIRST()
  ->then(sub { SECOND () })
  ->else(sub {
     CATCH()
  });

Conditional execution can be performed by using a regular if inside a then_with_f sequence, to return either a new or the original future:

FIRST();

if( $COND ) {
  SECOND();
}
FIRST()
  ->then_with_f(sub { my ( $f ) = @_;
    if( $COND ) {
      return SECOND() }
    return $f; });

Repeated loops such as do {} while can be implemented using Future::Utils::repeat():

do {
  BODY()
} while( $COND )
repeat {
  BODY();
} while => sub { $COND };

A pre-condition while {} loop is a little trickier because it still needs a future to return if the loop body doesn't execute at all. The simplest way is simply to skip the repeat call if it isn't required:

 
while( $COND ) {
  BODY();
}
!$COND ? Future->new->done()
    : repeat {
        BODY();
      } while => sub { $COND };

A foreach {} loop can also be written using repeat:

foreach my $VAR ( @LIST ) {
  BODY();
}
repeat { my $VAR = shift;
  BODY();
} foreach => [ @LIST ];

The values generated by a map {} call can be created using Future::Utils::fmap:

my @values = map {
  BODY();
} @LIST;
my $value_f = fmap {
  BODY();
} foreach => [ @LIST ];

In every case here, the future version of the control flow structure yields a future, which of course can then be combined inside other structures as required:

do {
  FIRST();
  foreach ( @LIST ) {
    SECOND($_);
  }
  if( $C ) {
    THIRD();
  }
} until( $HAPPY )
repeat {
  FIRST()
    ->then(sub { repeat {
      SECOND(shift);
    } foreach => [ @LIST ] })
    ->then_with_f(sub { my ( $f ) = @_;
      if( $C ) { return THIRD(); }
      return $f; });
} until => sub { $HAPPY };

<< First | < Prev | Next >


Edit 2013/12/29: Updated to use then_with_f

2013/12/21

Futures advent day 21

Day 21 - Implementing Timeouts

Suppose now we have a function called TIMEOUT(), similar to SLEEP() except it returns a future that will fail at some later time. We can combine this with another future using the wait_any combination function, to create a timeout. Like needs_any and needs_all, this combination function takes a list of futures and returns a future representing their combination. In this case the combination will complete as soon as any of the individual futures completes, regardless of success or failure. At this point, any other pending futures are cancelled.

my $f = Future->wait_any(
  GET( "http://my-site-here.com/might-be-slow" ),
  TIMEOUT( 20 ),
);

my $page = $f->get;

Here we are using wait_any to add timeout behaviour to a page get operation. If the HTTP operation either succeeds or fails before the 20 seconds are up then $f will complete with the same result or failure, and the timeout will be cancelled. Alternatively, if it still has no result after 20 seconds then the timeout future will fail, causing the overall future $f to fail, and the HTTP operation will be cancelled. In this way we can easily add timeout behaviour to any future-returning function, without every operation individually having to implement timeouts of any kind.

<< First | < Prev | Next >

2013/12/20

Futures advent day 20

Day 20 - Automatic Cancellation

A few days ago we saw two similar ways to combine a list of futures into a single future; needs_all and needs_any. In both of these combinations it can happen that the combined future has its result determined before all of its components are ready - needs_all if any component fails, or needs_any if any component is successful. In that case there is no need to continue running the remaining operations, as their outcome cannot further influence the combination.

Yesterday we saw how futures support a cancel operation which cascades back up the tree of operations, causing individual components of an action to be cancelled, and generally all the operations halted. Naturally, both needs_all and needs_any will do this when they are cancelled, causing all of their still-pending components to be cancelled. But additionally, both will cancel remaining pending futures automatically when their result is already known. needs_all will cancel any futures that remain pending when it has to fail because a component failed, and needs_any will cancel any that remain when it already has a result.

For example, recalling day 13 where we first saw needs_all:

my $f = Future->needs_all(
  GET( "http://my-site-here.com/page1" ),
  GET( "http://my-site-here.com/page2" ),
  GET( "http://my-site-here.com/page3" ),
);

my @pages = $f->get;

As was mentioned before, if any of these page fetches fails then the overall operation will fail too, and the get method will throw this exception. What wasn't mentioned before is that since at this point any other pending fetch operations have no further bearing on the result of the combined future, there is no need to continue running them. In this situation needs_all will cancel them.

<< First | < Prev | Next >

2013/12/19

Futures advent day 19

Day 19 - Cancellation

As a future is a first-class object that represents an ongoing operation or activity, it serves as an ideal place to interact with that activity. As well as waiting for success or failure of this operation, we can also cancel it midway through by using the cancel method.

my $f = repeat {
  my ( $prev ) = @_;
  SLEEP($prev ? 10 : 0)->then( sub {
    GET("http://my-site-here.com/try-a-thing");
  });
} until => sub { $_[0]->get->code == 200 };

$SIG{INT} = sub { $f->cancel };

$f->get;

Here we have started an HTTP GET operation in a repeat loop, hoping to eventually achieve a success. If in the meantime the user gets bored and hits Ctrl-C, the SIGINT handler cancels the future representing the repeat loop. This will cause it to not continue executing another attempt, and also cascades the cancel call into its currently-running attempt. This cancel call continues to cascade down towards the individual basic futures that the entire operation is composed of. The behaviour of the then chain, for example, depends on how far the operation has progressed; in this case cancelling either the SLEEP or the GET.

The basic futures provided by event systems (such as the SLEEP call) can use the on_cancel method to register a code block to call if the future is cancelled. This could perhaps stop the event that they would use to implement the timer behaviour.

sub SLEEP {
  my ( $delay ) = @_;

  my $f = Future->new;

  my $id = EventSystem->timed_event(
    $delay, sub { $f->done }
  );

  $f->on_cancel( sub {
    EventSystem->stop_timed_event( $id );
  });

  return $f;
}

This cascading of cancellation requests allows future-based code to easily support cancelling partially-complete operations without having to implement the logic to track progress and direct the request appropriately. Simply provide on_cancel handlers for the basic future operations that make the overall activity and the request will be handled appropriately.

<< First | < Prev | Next >

2013/12/18

Futures advent day 18

Day 18 - Using fmap Concurrently

The main difference between these seemingly-similar utilities of repeat and fmap is that repeat is intended for performing a given action repeatedly where each attempt may in some way depend on the result of the previous, whereas fmap is intended for performing a given action independently across a given list of items. Because these attempts are independent, there is no requirement to run just one of them at once. As we are able to perform actions asynchronously and concurrently using futures, it makes sense to allow fmap to do this. This is done by passing a number to the concurrent argument of fmap.

my $f = fmap {
  my ( $id ) = @_;
  GET("http://my-site-here.com/items/$id")
} foreach => [ 1 .. 200 ],
  concurrent => 10;

my @pages = $f->get;

The fmap utility can then start as many concurrent HTTP GET operations as we have asked for, 10 in this case, and tries to keep this number of them running as they complete; starting another each time. When finally all of them are complete, the returned $f itself then completes, giving the results as before.

Because we are now running multiple operations concurrently, it could be the case that the ten concurrently-running items complete in a different order than the order the IDs appeared in the original list. fmap takes care of this, ensuring it returns results from the $f->get call in the original input order regardless. It behaves similar to a perl map {} operator, concatenating the results of each individual attempt. Because it can't know in advance how many results will come back and in which order, to achieve this concatenation it has store the results of each call into a list of array references, and flatten it at the end when it is returned. Often this is unnecessary as we know each attempt will only yield a single reply - in this case we can use the more efficient fmap1, which takes exactly one result from each attempt.

my $f = fmap1 {
  my ( $id ) = @_;
  GET("http://my-site-here.com/items/$id")
} foreach => [ 1 .. 200 ],
  concurrent => 10;

my @pages = $f->get;

In other situations we may not even need to return any results at all, and are using it simply to iterate a block of code concurrently (rather than using repeat). For that situation, fmap_void is similar again, but does not bother to collect results at all; when it completes it yields an empty list from its future.

<< First | < Prev | Next >

2013/12/17

Futures advent day 17

Day 17 - Returning a List of Results

We have now seen how Future::Utils::repeat can create control structures to repeatedly run a piece of code returning a future, until some ending condition occurs. When it finishes, the result of the repeat future yields the value of the final attempt it tried.

Sometimes though, we want to run an operation repeatedly and collect up all the results it yielded, rather than just the final one. If we have a list of things to iterate on and perform an operation on each we may wish to gather all the results from this. To do that we can use Future::Utils::fmap.

my $f = fmap {
  my ( $id ) = @_;
  GET("http://my-site-here.com/items/$id")
} foreach => [ 1 .. 200 ];

my @pages = $f->get;

Similar to the cases of repeat, here the returned future once again represents the overall operation of running the loop, and will only complete once the loop has finished running. Each item in the foreach list is given to each call to the code block inside. However, instead of the future yielding just the last result, all of the results are collected up and returned in a list.

<< First | < Prev | Next >

2013/12/16

Futures advent day 16

Day 16 - Iterating Over a List

Yesterday we looked at the repeat utility, and how it can form a future representing a repeated sequence of attempts to perform some action, when each attempt returns a future to represent it. That example used the result of each attempt to decide if the overall operation should be considered a success, or to have another go.

Sometimes, the number of times to run a loop is known in advance, or at least does not depend on the result, because we wish instead to iterate over items of some given input data. To perform this we can use repeat like a perl foreach {} loop, taking a list of items from an array reference, and invoking the action block once for each item in the list. As before, it returns a future which this time will complete once the input list is exhausted and the final item's attempt has completed.

my %items = ...;

my $f = repeat {
  my ( $key ) = @_;
  PUT("http://my-site-here.com/items/$key",
    $items{$key}
  )
} foreach => [ keys %items ];

$f->get;

Because a foreach list is provided, the repeat function passes the body code successive values from it on each iteration. We don't need to supply a while or until condition here, because the loop knows to terminate when the list is exhausted.

<< First | < Prev | Next >

2013/12/15

Futures advent day 15

Day 15 - Performing an Action Repeatedly

So far in this series we have been performing future-based actions that might succeed, or might fail, and combined them up into larger operations of success or failure. One fairly standard way of handling failures in application logic is by attempting to retry. We couldn't simply put a future get call inside a perl while {} loop, because then the loop itself would block until success and we couldn't do anything else at the same time.

Instead, we can use a function from the Future::Utils package called repeat. This takes a block of code which returns a future, and returns a future representing the operation of repeatedly calling that code and waiting for its future to finish, until some ending condition is satisfied. This condition is specified by a second block of code given as either the until or while arguments.

use Future::Utils qw( repeat );

my $f = repeat {
  POST("http://my-site-here.com/new", $form)
} until => sub { $_[0]->get->code == 200 };

my $page = $f->get;

Each time around the loop we will attempt to POST to the resource. When this HTTP operation finishes the until condition is tested. In this example, we are looking for a 200 OK response from HTTP. If we get any other response, we'll try again. The entire operation is represented by the future returned in $f. When we eventually get a response that is deemed acceptable, the overall future $f will receive its result.

In this rather simple example we'll retry each attempt immediately, with no limit on the number of retries. A more practical example would apply a delay between each call, and limit the number of retries. Let us now suppose we have a sleep-like function, DELAY, which returns a future that will complete some number of seconds later.

my $retries = 5;

my $f = repeat {
  my ( $prev ) = @_;

  DELAY($prev ? 10 : 0)
    ->then( sub {
      POST("http://my-site-here.com/new", $form)
    })
} while => sub { $_[0]->get->code != 200 and
                 $retries-- };

my $page = $f->get;

Here we keep a count of the number of retry attempts, and stop retrying once we run out of them. We can implement the pause between retries by asking the DELAY function for a pause of either 0 or 10 seconds, depending on whether there had been a previous failure (this being indicated by the presence or absence of the previous future being passed in to the code body).

<< First | < Prev | Next >

2013/12/14

Futures advent day 14

Day 14 - Waiting for Alternatives

Yesterday's look at needs_all was our first look into an actual concurrent use-case where we can really benefit from the asynchronous nature of a Future, to combine multiple page requests concurrently and wait for them all to respond.

Today we look at a similar function, needs_any, which also takes a list of individual futures and returns a new future to represent their combination. In this instance, the new future will complete the first time any of its components completes successfully, or will fail once all of its individual components have failed.

my $f = Future->needs_any(
  GET( "http://uk.my-site-here.com/cache/a" ),
  GET( "http://de.my-site-here.com/cache/a" ),
  GET( "http://us.my-site-here.com/cache/a" ),
);

my $resp = $f->get;

Here we have started three different HTTP GET operations from three different servers, in the hope that whichever one is closest will respond first, thus making the overall future return the page. If that server happened to return an error, this will be ignored while there are still other alternatives available. The overall future will only yield an error if all the servers do. This gives us an easy way to attempt a variety of strategies to provide an answer to a given question.

<< First | < Prev | Next >

2013/12/13

Futures advent day 13

Day 13 - Waiting For Multiple Futures

Yesterday we took our first look at some actually-asynchronous uses of a Future, by taking a look at Net::Async::HTTP, but so far in this series we haven't actually seen anything that properly makes use of a Future, that could not be done just as easily synchronously.

Now we can take our first look at some code that uses the asynchronous nature of an HTTP user agent to fetch multiple resources concurrently. By using the Future->needs_all constructor we can create multiple futures to fetch individual pages, then combine them together into a single future which we can then wait on by calling get.

my $f = Future->needs_all(
  GET( "http://my-site-here.com/page1" ),
  GET( "http://my-site-here.com/page2" ),
  GET( "http://my-site-here.com/page3" ),
);

my @pages = $f->get;

Here we have created three individual futures representing an HTTP page GET, and wrapped them all in a single wrapper future which will complete when all of its components are complete. The get call on this future then returns a list composed of the result of each individual future. Because we know each one only returns the HTTP::Response object itself, we can just get these as a list. If any of the individual HTTP GET futures fails, the overall combined future will fail too. This means we can neatly handle any exceptions that happen.

When using a properly asynchronous HTTP user agent we are now able to perform these multiple GETs concurrently. Each call to GET starts the fetch operation, which can now all complete concurrently eventually returning their results. This is our first real example of futures providing neat concurrency-enabling code.

<< First | < Prev | Next >

2013/12/12

Futures advent day 12

Day 12 - Asynchronous Await

Up until now in these posts I have been deliberately vague on the subject of how the HTTP GET function actually works. All I have implied is that it takes a page URL and returns a Future that will eventually yield an HTTP::Response containing the resource. As I said right back in the first post on day 1, Futures work just fine if every result is in fact a synchronous return. Thus, we could choose to implement an entirely synchronous version of this function using LWP::UserAgent (and taking care not to confuse its get method with the unrelated Future one):

use Future;
use LWP::UserAgent;
my $ua = LWP::UserAgent;

sub GET
{
  my ( $url ) = @_;
  
  Future->call( sub {
    Future->wrap( $ua->get( $url ) )
  });
}

Here we have used Future->wrap to conveniently create a future to contain the result of a successful call to the UserAgent's get method (remember, this is HTTP GET and unrelated to the future get method). This call is itself wrapped in a Future->call block to ensure that if the UserAgent throws an exception, this will be wrapped in a failed future.

Alternatively, if we wanted some level of asynchronous behaviour, because we wish to perform multiple concurrent actions, or mix this with other code, we could instead use Net::Async::HTTP which already provides a GET method having the semantics we want:

use IO::Async::Loop;
use Net::Async::HTTP;

my $loop = IO::Async::Loop->new;
my $http = Net::Async::HTTP->new;
$loop->add( $http );

sub GET
{
  my ( $url ) = @_;
  return $http->GET( $url );
}

This one is implemented internally by Net::Async::HTTP returning a subclass of Future provided by IO::Async itself. This subclass understands how to wait for futures that are not yet ready, by invoking the containing loop until the result is available. Other event systems can be similarly catered for by subclassing Future to provide a suitable await method, which is used by get. We could even, if we were inclined towards threads, implement a subclass of Future which used some kind of thread-based synchronisation and communication to await the result being supplied by code running in a different thread.

Because they both conform to the interface of "returning a Future", either of these above implementations of GET are suitable for any of the examples we have seen so far, or will see in the next examples to come. So too would any other implementation that provides this interface. Because of this we find that Futures provide a powerful way to write the intermediate layers of processing and "business logic" in application libraries, which can remain agnostic on such low-level details as what event system is being used, or even if one is being used at all.

<< First | < Prev | Next >

2013/12/11

Futures advent day 11

Day 11 - Transforming Results or Failures

While we are on the subject of convenient shortcuts to neaten up certain kinds of Future result handling, another common pattern that arises is the case of an immediate return; either a then block that returns an immediate result based on the given values, or an else block that returns an immediate failure based on the given one. In each of these cases the transform method allows us to write this more conveniently.

sub GET_title
{
  my ( $url ) = @_;

  GET_checked($url)->transform(
    done => sub { get_page_title( $_[0] ) },
  );
}

If the GET_title is successful then the code passed in the done argument is invoked with the result as the argument list, and whatever it returns is used as the result of the future that transform returned. This is a little shorter and more convenient than the functionally-equivalent then block returning an immediate future.

We can similarly use transform on the failure message to create a different message, perhaps with more details in it.

sub GET_title
{
  my ( $url ) = @_;

  GET_checked($url)->transform(
    done => sub {
      get_page_title( $_[0] )
    },
    fail => sub {
      my $message = shift;
      "Cannot get title of $url - $message", @_;
    }
  );
}

Because the failure may contain other values giving more context, we need to be careful to preserve them. This is done most easily by shifting the message, so the remaining values appear in @_.

<< First | < Prev | Next >

2013/12/10

Futures advent day 10

Day 10 - Conditional Chaining

Over the past few days we have seen uses of then and else to chain sequences of code together. Sometimes the code in a then or else block will inspect its given arguments, and decide that it doesn't in fact want to perform any other action so just returns a new Future containing the same values again.

Instead of this, we can use the methods then_with_f and else_with_f, which are variations of then and else which pass the code block the actual Future object they are invoked on in addition to the result or failure list it contains. The code can then either construct a new Future containing different results, or just return that one directly.

sub GET_checked
{
  my ( $url ) = @_;

  GET( $url )->then_with_f( sub {
    my ( $f, $resp ) = @_;

    return $f if $resp->code =~ m/^[23]../;

    return Future->new->fail($resp->code." ".$resp->message, $resp);
  });
}

This is not only neater and clearer to read, but is also more efficient because it doesn't need to create yet another Future object just to contain the same result that the one it was invoked on already had. Equally, an else_with_f can neaten up the way we sometimes simply propagate a failure if we decide not to handle it.

my $f = GET_checked("http://my-site-here.com/a-page")
  ->else_with_f( sub {
     my ( $f, $failure, $response ) = @_;

     return $f if $response->code != 500;

     return Future->new->done(
       HTTP::Response->new( 200, "OK", [],
         "Server is down, but have some fluffy kittens instead")
     );
  });

<< First | < Prev | Next >


Edit 2013/12/29: Updated for then_with_f and else_with_f

2013/12/09

Futures advent day 9

Day 9 - The call and wrap methods

Over the past few days of code, a couple of common patterns have arisen. The first is that often a then or else block wishes to simply return a future immediately containing some results. Until now we have used the done method on a new future, which returns the future itself. Because this happens so often, a slightly neater (and internally more-efficient) form can be used instead, by using the wrap class method:

$f = Future->wrap( @values );

This is equivalent to constructing a new future and setting the values on it, except in the case that it was invoked with exactly one argument, and that argument was already a Future object. In that case, the future is returned directly.

Another pattern is that a block of code is called, and if it throws an exception it instead returns a future with that exception as its failure. The call class method takes a block of code and does this; returning either an immediately failed future if the code died, or returns the future that the code itself returned if it did not throw an exception.:

$f = Future->call( sub { ... } );
$f = Future->call( \&func, @arguments );

<< First | < Prev | Next >

2013/12/08

Futures advent day 8

Day 8 - Handling Successes and Failures

We have seen how the then and else methods allow us to chain a sequence of code together, dependent on whether the previous succeeded or failed, in order to implement control flow that processes values and handles exceptions. Because each code block itself returns a future, we can "catch" exceptions and turn them into successful results, or we can throw "exceptions" if we don't like a successful result we received. However, sometimes it's convenient to split the control flow after a future, invoking a choice of two different code blocks depending on its success or failure. This way, the "then" handling code isn't going to be confused by a successful return from an exception handler, nor is the "else" code going to get confused if the "then" block dies. To do this, we can use the two-argument version of then.

my $f = GET("http://my-site-here.com/news")
  ->then(
    sub { # on success
      my ( $response ) = @_;
      my $title = get_page_title( $response->content );
      return Future->new->done( $title );
    },
    sub { # on failure
      my ( $failure, $response ) = @_;
      if( $response->code == 204 ) { # No Content
         return Future->new->done( "(no title)" );
      }
      return Future->new->fail( $failure, $response );
    },
  );

It would not have been possible to easily write this code by a sequence of single-argument then and else; because either the else block following the then would be confused by any exceptions thrown by the get_page_title() function, or the then block following the else would be confused by receiving a string rather than the HTTP response. While this could be detected by checking the types of the arguments, it turns out to be more useful and safer in practice to have a two-argument form of then which splits the control flow appropriately.

<< First | < Prev | Next >

2013/12/07

Futures advent day 7

Day 7 - Failures with Values

Yesterday we saw how we can use an else block to catch an exception and make it return a different value, including a success. Of course, it was a rather blunt way to handle a failure because it just turned any failure into a 599 HTTP status.

This is perhaps a good time to explain that, like done can be passed a list of multiple values for on_done and then to receive, so too can fail. The first value in this list must be true and ought to be well-behaved as a string, because get will use it as the exception it will die() with if it has to. Any other values in the list are ignored by get, but are passed in to on_fail and else.

Lets now make a better version of GET_checked that passes the failing HTTP response along with the failure.

sub GET_checked
{
  my ( $url ) = @_;

  GET( $url )->then( sub {
    my ( $r ) = @_;
    if( $r->code !~ m/^[23]../ ) {
      return Future->new->fail( $r->code." ".$r->message, $r );
    }
    else {
      return Future->new->done( $r );
    }
  });
}

We can now handle our errors better by only masking one kind of error that we are interested in.

my $f = GET_checked("http://my-site-here.com/a-page")
  ->else( sub {
     my ( $failure, $response ) = @_;

     if( $response->code != 500 ) {
       return Future->new->fail( $failure, $response );
     }

     return Future->new->done(
       HTTP::Response->new( 200, "OK", [],
         "Server is down, but have some fluffy kittens instead")
     );
  });

my $response = $f->get;

Now if the server fails with a 500 error, we will think of fluffy kittens instead. But any other error is still reported as a real failure.

<< First | < Prev | Next >

2013/12/06

Futures advent day 6

Day 6 - Control Flow with Failures

We have now seen how done is used to mark a Future as successfully complete thus causing its get method to return, and how then is used to create a chain of activity between them when they succeed. We have also seen how fail can be used to mark a Future as having failed thus causing its get method to throw the exception. We can complete this set of methods by adding else, which is used to chain an activity after a Future if it fails.

my $f = GET("http://my-site-here.com/a-page")
  ->else( sub {
    return Future->new->done(
      HTTP::Response->new( 599, "Failed", [], "GET failed" )
    );
  });

my $response = $f->get;

Here we are using else to act as a kind of try/catch block, taking any exception and turning it into a successful response instead. If the GET future returns successfully, the else code doesn't get to run; instead the success gets passed right through to $f.

<< First | < Prev | Next >

2013/12/05

Futures advent day 5

Day 5 - Causing a Future to fail

Yesterday we looked at how to handle a Future that has failed. We can cause a Future to fail by invoking its fail method instead of done.

sub GET_checked
{
  my ( $url ) = @_;

  GET( $url )->then( sub {
    my ( $r ) = @_;
    if( $r->code !=~ m/^[23]../ ) {
      return Future->new->fail( $r->code." ".$r->message );
    }
    else {
      return Future->new->done( $r );
    }
  });
}

Here we have created a checked version of our hypothetical HTTP GET function, which returns a Future that will only be successful if the HTTP response was in the 2xx or 3xx ranges. If it gets an error (4xx or 5xx) then the Future will fail.

Another way to cause a future to fail is to simply throw a regular perl exception from a then or else code block. Each call to a code reference passed to these methods is wrapped in a eval {} block and causes the future to fail if the code throws an exception. This makes it easier to handle because now the chained future will fail, rather than causing the code that marked the preceding future as complete to propagate the exception it threw.

my $f = GET_checked("http://my-site-here.com/products.xml")
  ->then( sub {
    my ( $response ) = @_;
    if( $response->content_type ne "text/xml" ) {
      die "Expected Content-type: text/xml";
    }
    return Future->new->done( $response );
  });

This code is equivalent to code which uses Future->new->fail - the caller will not directly die with that exception, but instead the returned future will fail.

<< First | < Prev | Next >

2013/12/04

Futures advent day 4

Day 4 - Coping with failure

So far every Future example we have seen has resulted in an eventual success. But, like regular perl functions can either return a result or die() an exception, so too can Futures either complete with a result or a failure. Whereas the on_done method attaches code to handle a successful result we can use on_fail similarly to attach code to handle a failure.

my $f = GET("http://my-site-here.com/");

$f->on_done( sub {
  my ( $response ) = @_;
  print "Got a response\n";
});

$f->on_fail( sub {
  my ( $failure ) = @_;
  print STDERR "It failed: $failure\n";
});

If the get method receives a failure on the Future instead of a success, it throws the message from that failure as a perl exception, causing the method to die instead of return. This leads to many cases of Future code being able to look and act very similarly to regular perl function calls, with values being returned, or exceptions being thrown and caught.

<< First | < Prev | Next >

2013/12/03

Futures advent day 3

Day 3 - Chaining Futures to perform a sequence of actions

A more powerful ability than on_done, and one which in practice turns out to be used much more often, is provided by the then method. This method itself returns a Future, and expects code that will return a Future when it is invoked. In this way it provides an ability to perform a second action which returns a Future after the first one completes, and returns a Future that represents the complete combination of the first and the second.

my $f = GET("http://my-site-here.com/first")
  ->then( sub {
    my ( $first_response ) = @_;
    my $path = path_from_response($first_response);
    GET("http://my-site-here.com/$path);
  });

my $second_response = $f->get;

In this second example after the first page has been returned we then fetch a second page by somehow using the result of the first page's response to give a path name for the second. The returned Future in $f will be complete after this second response has been received. The call to get will then wait for this to happen.

Of course, we are not limited to simply two actions - because the then method returns another Future, we can simply call then on that as well to chain as many steps of a process as are necessary to complete it. This leads to a neat sequence of code, quite unlike the ever-indenting nature of passing callback functions.

<< First | < Prev | Next >

2013/12/02

Futures advent day 2

Day 2 - Doing something when a Future completes

Because a Future object represents an operation that is currently in progress or has finished it provides the ideal place to attach logic to ask for further activity to happen when the original has completed. The most immediate way is to pass a piece of code in a sub reference to the on_done method.

my $f = GET("http://my-site-here.com/");

$f->on_done( sub {
  my ( $response ) = @_;
  print "Got a response\n";
});

In this case, as for many posts yet to come, we are presuming some hypothetical GET function that returns a Future wrapping an HTTP operation in the obvious manner.

If the returned Future is already complete (perhaps because it is a synchronous client that always completes immediately, or because it was served internally from a cache) then the on_done method invokes the code immediately. If not, the code is stored inside the Future object itself for when it eventually gets its result.

<< First | < Prev | Next >

2013/12/01

Futures advent day 1

It is traditional around this time of year for Perl blogs to publish an advent calendar - a series of 24 short little posts around a common theme.

People have suggested I might write one about Futures, so here goes...

Day 1 - Futures can return values synchronously

You don't in fact have to use a Future for anything asynchronous. A simple synchronous-returning function can use them too.

use Future;

sub sum
{
   my @numbers = @_;
   my $total = 0;
   $total += $_ for @numbers;
   return Future->new->done( $total );
}

say "The total is " . sum( 10, 20, 30 )->get;

It may not be immediately obvious currently why you want to do this, but I hope to motivate why over the following 23 posts...

<< First | < Prev | Next >

2013/10/23

Parallel Name Resolving using IO::Async

Perl has a variety of modules and frameworks that allow multiple, parallel operations at once. Some are specific to one kind of task, and some more generic. One of the larger general-purpose ones is IO::Async.

IO::Async provides an abstraction around the system name resolver, getaddrinfo(), allowing it to be called asynchronously to resolve a number of names at once, and returning results later as they arrive.

To do this, start with the resolver object itself. This can be obtained from the underlying IO::Async::Loop object. We do not actually need to keep a reference to the Loop, as the resolver will keep that itself.

use IO::Async::Loop;

my $resolver = IO::Async::Loop->new->resolver;

Next, call the getaddrinfo method on it, passing in the details of the name lookup required, and collect the result list. We need to pass a hint to the method so that it returns just one kind of socket address rather than iterating all the possible kinds. Since we only care about the IP address and not the service port number it doesn't matter too much what hint we pass, but one of the simpler ones is to ask for the stream socket type (i.e. TCP ports).

my @results = $resolver->getaddrinfo(
   host     => "www.google.com",
   socktype => 'stream',
)->get;

This method is intended for creating packed socket address structures for passing directly to connect() or bind(), so to obtain a human-readable string it will need converting back to a printable numeric form by using Socket::getnameinfo(). We need to pass in the NI_NUMERICHOST flag in order to have it return a plain numeric IP address instead of reverse resolving that address back into a name. The numeric address string itself will come in the second positional result from getnameinfo(), so we will have to use a list slice operator to return just that.

use Socket qw( getnameinfo NI_NUMERICHOST );

my @addrs = map { ( getnameinfo $_->{addr}, NI_NUMERICHOST )[1] }
            @results;

print "$_\n" for @addrs;

This yields the list of IP addresses for this one hostname:

2a00:1450:4009:809::1014
173.194.34.112
173.194.34.115
173.194.34.113
173.194.34.116
173.194.34.114

The reason for the get method here is that, like (almost) all of the IO::Async methods that perform a single asynchronous operation, the getaddrinfo method returns a Future. A Future is an object representing an outstanding operation that may not yet be complete. In this first simple example we simply wanted to wait for that operation to complete, so we forced it by calling the get method on it. This method waits for the Future to be complete then returns its result.

Of course, the entire reason for our using IO::Async was to perform multiple operations at the same time, and wait concurrently for them all to complete. So rather than calling get on each individual getaddrinfo future, we can combine them all together into a single future that needs them all to complete before it itself is considered completed.

my @hosts = qw( www.google.com www.facebook.com www.iana.org );

my @futures = map {
   my $host = $_;
   $resolver->getaddrinfo(
      host     => $host,
      socktype => 'stream',
   )
} @hosts;

my @results = Future->needs_all( @futures )->get;

my @addrs = map { ( getnameinfo $_->{addr}, NI_NUMERICHOST )[1] }
                @results;

print "$_\n" for @addrs;

This now yields:

2a00:1450:4009:809::1011
173.194.41.180
173.194.41.177
173.194.41.179
173.194.41.176
173.194.41.178
2a03:2880:f00a:401:face:b00c:0:1
31.13.72.65
2620:0:2d0:200::8
192.0.32.8

Oh dear. Unfortunately, the needs_all future has simply concatenated all of the individual results together, so we have lost track of which host has which addresses. To solve this, we can make each individual host future return not a list of its results, but a two-element list containing its hostname and an ARRAY ref of the IP addresses it resolved to. That way, when we fetch the results of the overall needs_all future we will have an even-sized name-value list, perfect for assigning into a hash.

To do this we can have each host future be a two-stage operation, consisting of first the getaddrinfo call, and then altering its result using a code block passed to the transform method.

my @futures = map {
   my $host = $_;
   $resolver->getaddrinfo(
      host     => $host,
      socktype => 'stream',
   )->transform(
      done => sub {
         my @results = @_;
         my @addrs = map { (getnameinfo $_->{addr}, NI_NUMERICHOST)[1] }
                         @results;
         return ( $host, \@addrs );
      }
   );
} @hosts;

my %addrs = Future->needs_all( @futures )->get;

use Data::Dump 'pp';
print STDERR pp(\%addrs);

Now we retain the mapping from hostnames to the list of IP addresses they resolved to:

{
  "www.facebook.com" => ["2a03:2880:f00a:201:face:b00c:0:1", "31.13.72.1"],
  "www.google.com"   => [
                          "2a00:1450:4009:809::1010",
                          "173.194.41.177",
                          "173.194.41.178",
                          "173.194.41.180",
                          "173.194.41.179",
                          "173.194.41.176",
                        ],
  "www.iana.org"     => ["2620:0:2d0:200::8", "192.0.32.8"],
}

Now, this post is fairly obviously written in response to Parallel DNS lookups using AnyEvent but from the perspective of IO::Async instead. Asides from the choice of event system, two important differences should be observed:

  • Through the use of futures, this example manages both the flow of control and data along with it. It does not need to declare variables that get captured by callback functions to cause data to flow separately from the way it uses an object to handle the flow of control. Each future object yields its result, and the individual futures can form linear flows by using transform or other methods to return different results, or needs_all or other methods to combine individual futures into larger ones.
  • Nowhere in the above did I mention DNS. This is intentional. IO::Async's getaddrinfo resolver really is an asynchronous wrapper around the underlying Socket function of the same name. Because of this it uses the system's standard name resolver as provided by libc, ensuring it will yield the same identical results as any other program using the system resolver, regardless of whether libc is configured to use DNS, files, LDAP, or any other resolution method. It also automatically handles IPv6 if the underlying system does; returning a mixture of IPv4 and IPv6 addresses in the host's preferred order. The caller does not need to be aware of the subtle distinctions of RFC 3484 sorting order, for example.

2013/09/30

Perl - Tickit - 0.40

Latest Tickit version (0.40) is now up on CPAN. Recent changes include:

  • Mouse drag-and-drop events (0.32)

    Windows now create more interesting events to represent mouse drag-and-drop operations. Starting, moving, and ending a mouse-drag all create events that can help widgets render more interesting behaviours.

  • Added Tickit::RenderBuffer (0.33)

    RenderBuffer is an in-memory buffer to store content that will eventually be rendered to the terminal. In effect it stores a double-buffer of content, allowing widgets to draw in whatever order is most convenient for them, before efficiently flushing it in a top-to-bottom manner.

    Being implemented in C/XS instead of Perl allows it to operate more efficiently than the previous-generation direct rendering to Windows. As it stores the content before rendering it also allows better handling of Unicode line-drawing characters; allowing for characters to be merged together out of multiple line segments, creating the ability for complex line-drawing shapes to be easily rendered.

  • Added timer support to core event loop (0.34)

    Widgets can now react to timed events, allowing for animation effects and other behaviours.

  • Focus management (0.34 and 0.35)

    Container widgets now provide management of the focus-chain order of their children, allowing the whole widget tree to maintain the "next" and "previous" direction of focusing. The base code handles the <Tab> and <Shift-Tab> key events to cycle input focus around the widget tree automatically.

  • Use RenderBuffer in favour of direct Window rendering (0.40)

    Now that RenderBuffer is in the core distribution, all widgets should be using it rather the previous render method to render directly on the window. This is a stepping-stone change to allow for further improvements.

  • New sizing model (0.40)

    New methods are provided by the base Tickit::Widget class that cache the requested size of the widget, and only inform the parent container when this size actually changes. This allows for more efficient reshaping and redrawing operations when widgets change their size requirements, without needing to recalculate the whole widget tree.

These final two changes help support a couple of interesting planned improvements:

  • Widget minimal/maximal size handling

    Because the base widget class now handles size information more directly, it can implement bounds on minimal and maximal widget size. These will be derived from Tickit::Style. It may also be possible to consider padding and margin controls in the base widget class and thus automatically apply to every widget.

  • Whole-tree rendering via RenderBuffer

    By adding area masks to RenderBuffer it should then support being used as a single buffer object to render the entire window hierarchy. Because the masking code will be implemented in C code, it will much more efficient than the current pure-perl Window-based solution involving visibility testing per character cell. This will allow for much more better redrawing performance.

    This will also allow RenderBuffer to move out of the Tickit.xs file and into libtickit itself, where it can be useful to non-Perl code (such as native C programs or other language bindings).

2013/08/30

Perl - constructors don't have to be called "new"

I've recently been writing a module to communicate with the Cassandra database server. Messages arrive from the server and are placed in objects called Frames, which have methods for extracting various protocol-sized items like integers, strings, etc.. A few helper objects exist which are structures formed by parsing messages out of Frame objects. (I won't go into detail what this all means in this post, as the details aren't important here).

Up until about half an hour before the first release, the constructors for these were just called new.

Protocol::CassandraCQL::Result->new( $frame )

But then I stopped, and had a thought. This operation isn't really creating a new result, as just extracting one from the frame. Requiring "the" constructor to be passed a Frame object also restricts the future direction of the API - perhaps one day I'll have to construct one from some direct arguments, or by parsing something else. Then I'd have to play awkward tricks like working out what types the constructor was passed.

If course, there's nothing special about the word new to Perl. The constructor could be called whatever we want, and it's only convention that we call them new. If I just call it something more sensible, then it easily leaves the way open to other constructors to be added another time. Plus it actually reads better, I think.

Protocol::CassandraCQL::Result->from_frame( $frame )

2013/07/23

Double-width and double-height in libvterm and pangoterm

I've been keeping a list of terminal sequences unrecognised by libvterm and pangoterm. For a while I've kept the DEC double-width line and double-height line sequences in there, because I wasn't sure how they would interact with the arbitrary scrolling rectangles defined by VT4xx. The VT400 manual doesn't really mention how to handle this, but by chance I happened to be reading a VT500 manual instead, which does. It explains that the double-width or -height sequences aren't recognised in SLRM (Set Left/Right Mode; newly renamed from the identical but differently-named Vertical Split-Screen Mode in VT400); and that enabling SLRM will revert all lines back to single-width, single-height.

This neatly handles the problem that would otherwise occur, in that these line modes apply to entire lines. If a partial scrolling operation were to affect such a line, what would happen to the double-width characters in it? By linking it with SLRM this is avoided - either the terminal is in a mode where double-width can happen, or it's an a mode where partial lines can be scrolled - but never both.

With this neatly resolved, I finally got around to implementing DECDHL and DECDWL in libvterm and pangoterm. Here's a screenshot showing the ever-useful vttest.

With this out of the way, the list of unsupported VT1xx features is rapidly diminishing. About all that's left asides real-hardware things like interlace mode (which will be impossible to do), is 80/132 column mode. That's another one I'm still not sure how to implement...

2013/05/07

Tickit version 0.31

(mostly a copy of the mail to the tickit-dev mailing list)

A lot of stuff happening lately. And also I haven't written one of these for ages. I won't go into every detail, but here's a rundown of the most interesting parts:

  • Rect/RectSet are now C library based (0.26)

    Fairly simple, no surprises here. C implementation means it's available in C and other languages, and probably a bit faster in actual use.

  • New Term event binding API (0.26)

    Rather than a single on_key/on_mouse/etc..., there is now just a list of possible event handlers. Event handling subs don't have to be restricted to a single event; each is registered with a bitmask. This is done to more closely match the C API.

    The existing Perl API of having a single on_* handler for each event type is still supported, by wrapping the newer API.

  • All windows are now FLOAT windows (0.28)

    As was first suggested in 0.23, all the windows now use the new float logic. The previous environment variable has now been removed. This hopefully shouldn't actually affect anything as it's been the default for a while now, but does simplify the code internals.

  • $win->close and no more weak references (0.28)

    Using weak references and relying on DESTROY works OK in some circumstances in Perl, but won't scale to C and other languages, and still makes for tricky logic. To this end, I've removed all the weaken()ing and replaced it with an explicit ->close method to remove a window. This also makes it much more robust in nontrivial cases.

    This change is mostly of interest to container widget developers, or in more dynamic long-lived programs.

  • Tickit::Style (0.29)

    This one's the big main one of the list; in fact so bit I'll probably write another mail. In summary; we now have something of a first attempt at being able to separate out style from widget implementations, in a way that's easy to add to application- or user-specific style files. More on this later.

  • Tickit::Pen now comes in mutable and immutable forms (0.30)

    Since most pens don't get mutated, and Tickit::Style performs better with cached pens, I've split the idea of a Pen into mutable and immutable types. Tickit::Style returns immutable pens, so widgets shouldn't attempt to mutate them.

    Tickit::Pen->new itself still returns a mutable pen for now, but in the future this may change; code that specifically wants a mutable or immutable pen should use the appropriate subclass.

  • Tickit::Pen changes to support upcoming Tickit::RenderContext (0.31)

    A few small changes that allow the new Tickit::RenderContext to work better.

Also some changes in the underlying libtickit C library:

  • Generic string/integer value termctl operations

    Primarily provided to let the xterm driver set the window title, etc..., but the general idea is something similar to ioctl(), so we don't have to extend the API a thousand times just to add lots of little options for specific terminals.

  • Split xterm/TI-based driver model

    To support more specific options in future, and also to give a better (or more accurate) terminfo-based driver. There are now two drivers, selected by the $TERM environment variable, so the xterm-specific things can be done nicely, and still arrange for the generic terminfo driver to work.

    This also allows for other terminal-specific drivers in future, in case we find those useful. Perhaps a Win32 console one too.

2013/03/18

Net::Async::HTTP::Server

Recently, I've been working on a way to serve HTTP with IO::Async. For a while it's been possible to use HTTP as a client with Net::Async::HTTP, so it seemed only natural to provide a server named Net::Async::HTTP::Server.

I've tried to design the interface fairly similar to some of the other server modules, most notably Net::Async::FastCGI. This allows for similar code to be written one way or the other, for responding via HTTP or FastCGI.

use Net::Async::HTTP::Server;
use IO::Async::Loop;
 
use HTTP::Response;
 
my $loop = IO::Async::Loop->new();
 
my $httpserver = Net::Async::HTTP::Server->new(
   on_request => sub {
      my $self = shift;
      my ( $req ) = @_;
 
      my $response = HTTP::Response->new( 200 );
      $response->add_content( "Hello, world!\n" );
      $response->content_type( "text/plain" );
 
      $req->respond( $response );
   },
);
 
$loop->add( $httpserver );
 
$httpserver->listen(
   addr => { family => "inet6", socktype => "stream", port => 8080 },
   on_listen_error => sub { die "Cannot listen - $_[-1]\n" },
);
 
$loop->run;
As with Net::Async::FastCGI the distribution also includes modules to support hosting a PSGI application via Plack. The Plack::Handler module in particular allows the use of Net::Async::HTTP::Server directly from the plackup commandline:

plackup -s Net::Async::HTTP::Server --listen ":8080" application.psgi

It's still in somewhat of an early state - while it supports sending streaming responses (as required by PSGI) it doesn't yet support streaming receiving of requests. That shouldn't be too hard to add, but so far I haven't found a need to add it yet.

2013/02/05

Alt modifier - high-bit or escape?

I've wanted to write this up for quite a while. Haven't quite got around to it mostly for not knowing how to start. So instead of agonising over an introduction, I'll just paste IRC logs instead.

#vim on Freenode, on a subject of whether terminals should encode the Alt modifier key by high-bit mask, or Escape prefix:

You -always- want alt-sends-escape. Anything about high-bits just breaks UTF-8 and is always broken.

alt==highbit => it is impossible to distinguish UTF-8 input from Alt-modified input. Cannot be done. All input is broken. Fail. Go home
alt==esc => it is possible to distinguish Escape prefix from Alt-modified input by using timing information. Not perfect, sometimes false hits, but generally works.

False positives happen if you type too quickly on a possibly-laggy connection, and multiple 1-byte writes coaless into a single 2-byte read buffer. False negatives ought not happen if your terminal is working nicely, but could be possible in buggy terminals (hello ConnectBot + Hackers' Keyboard), or if e.g. network MTU issues start cutting your buffers in weeeeird places.

I recommend 20msec.

20 is good because the human eye/brain will fudge over intervals shorter than 20 msec.. if two things happen within 20msec, or something that you expect to happen, happens within 20msec after, you'll perceive it as instant.

So a 20msec escape timeout means your brain doesn't notice that 20msec delay after you press the Escape key, before it hits back to Normal mode again. But 20msec is looooads of time for vim to wait for the trailing letter that might just be coming after the ESC byte if it was in fact an Alt- modified key.

Incidentally, this is the style used by my libvterm terminal emulator library, and libtermkey terminal key event input library.