Callback-Frame

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

          my $var = 123;
          $callback = sub { $var };
        }
        print $callback->();

    will print 123 even though $var is no longer in scope when the callback
    is invoked.

    Sometimes people call these anonymous functions that reference variables
    in their surrounding lexical scope "closures". Whatever you call them,
    they are essential for convenient and efficient asynchronous
    programming.

    For many applications we really like straightforward callback style. The
    goal of Callback::Frame is to simplify the management of dynamic
    environments (defined below) while leaving callback style alone.

DESCRIPTION
    The problem that this module solves is that although closures preserve
    their lexical environment, they don't preserve error handlers or "local"
    variables.

README  view on Meta::CPAN

    IMPORTANT NOTE: All callbacks that may be invoked outside the dynamic
    environment of the current frame should be created with "frame" or "fub"
    so that the dynamic environment will be correctly re-applied when the
    callback is invoked.

    The "frame_try" and "frame_catch" subs are equivalent to a call to
    "frame" with "code" and "catch" parameters. However, unlike with
    "frame", the frame is executed immediately.

    "frame_void" takes a single callback argument. This can be useful if you
    wish to kick off an unassociated asynchronous action while handling. If
    the action is run in void context, there is no way for it to throw an
    exception that will affect your request, or to access its local
    variables. Note that you probably should install a separate
    "frame_catch" in case the unassociated operation throws exceptions.

    Libraries that wrap callbacks in frames can use the
    "Callback::Frame::is_frame()" function to determine if a given callback
    is already wrapped in a frame. It returns true if the callback is
    wrapped in a frame and is therefore suitable for use with
    "existing_frame". Sometimes libraries like to automatically wrap a

README  view on Meta::CPAN


    "existing_frame" is also useful for extracting/setting a callback's
    local variables.

    Although you should never need to, the internal frame stack can be
    accessed at $Callback::Frame::top_of_stack. When this variable is
    defined, a frame is currently being executed.

NESTING AND STACK-TRACES
    Callback::Frame tries to make adding error handling support to an
    existing asynchronous application as easy as possible by not forcing you
    to pass extra parameters around. It should also make life easier because
    as a side effect of adding error checking it also can be made to produce
    detailed and useful "stack traces" that track the callback history of
    some connection or transaction.

    Frames can be nested. When an exception is raised, the most deeply
    nested "catch" handler is invoked. If this handler itself throws an
    error, the next most deeply nested handler is invoked with the new
    exception but the original stack trace. If the last "catch" handler
    re-throws the error, the error will be thrown in whatever dynamic

README  view on Meta::CPAN

    your frames things like "accepted connection from $ip:$port at $time"
    and "connecting to $host (timeout = $timeout seconds)".

    All frames you omit the name from will be shown as "ANONYMOUS FRAME" in
    stack-traces.

    Since multiple frames can be created within the same parent frame and
    therefore multiple child frames can be active at once, frames aren't
    necessarily arranged in terms of a stack. Really, the frame "stack" is
    more of a tree data structure (known in lisp as a "spaghetti stack").
    This occurs most often when two asynchronous request frames are started
    up concurrently while the same frame is in effect. At this point the
    "stack" has essentially branched. If you are ever surprised by an
    exception handler being called twice, this is probably what is
    happening.

"LOCAL" VARIABLES
    In the same way that using "frame_catch" or the "catch" parameter to
    "frame" preserves the dynamic environment of error handlers, the
    "frame_local" function or "local" parameter to "frame" can be used to
    preserve the dynamic environment of local variables. Of course, the

lib/Callback/Frame.pm  view on Meta::CPAN


    my $callback;
    {
      my $var = 123;
      $callback = sub { $var };
    }
    print $callback->();

will print C<123> even though C<$var> is no longer in scope when the callback is invoked.

Sometimes people call these anonymous functions that reference variables in their surrounding lexical scope "closures". Whatever you call them, they are essential for convenient and efficient asynchronous programming. 

For many applications we really like straightforward callback style. The goal of Callback::Frame is to simplify the management of dynamic environments (defined below) while leaving callback style alone.


=head1 DESCRIPTION

The problem that this module solves is that although closures preserve their lexical environment, they don't preserve error handlers or C<local> variables.

Consider the following piece of B<broken> code:

lib/Callback/Frame.pm  view on Meta::CPAN

    $watcher = AE::io $sock, 0, sub { do_stuff() };

In order for the callback to have its dynamic environment maintained, you just need to change it to this:

    $watcher = AE::io $sock, 0, fub { do_stuff() };

B<IMPORTANT NOTE>: All callbacks that may be invoked outside the dynamic environment of the current frame should be created with C<frame> or C<fub> so that the dynamic environment will be correctly re-applied when the callback is invoked.

The C<frame_try> and C<frame_catch> subs are equivalent to a call to C<frame> with C<code> and C<catch> parameters. However, unlike with C<frame>, the frame is executed immediately.

C<frame_void> takes a single callback argument. This can be useful if you wish to kick off an unassociated asynchronous action while handling. If the action is run in void context, there is no way for it to throw an exception that will affect your re...

Libraries that wrap callbacks in frames can use the C<Callback::Frame::is_frame()> function to determine if a given callback is already wrapped in a frame. It returns true if the callback is wrapped in a frame and is therefore suitable for use with C...

    if (!Callback::Frame::is_frame($callback)) {
      $callback = frame(code => $callback);
    }

If you wish to run a coderef inside an existing frame's dynamic environment, when creating a frame you can pass in an existing frame as the C<existing_frame> parameter. When this frame is executed, the C<code> of the frame will be run inside C<existi...

    frame(existing_frame => $callback, code => sub {

lib/Callback/Frame.pm  view on Meta::CPAN

    })->();

C<existing_frame> is also useful for extracting/setting a callback's local variables.

Although you should never need to, the internal frame stack can be accessed at C<$Callback::Frame::top_of_stack>. When this variable is defined, a frame is currently being executed.



=head1 NESTING AND STACK-TRACES

Callback::Frame tries to make adding error handling support to an existing asynchronous application as easy as possible by not forcing you to pass extra parameters around. It should also make life easier because as a side effect of adding error check...

Frames can be nested. When an exception is raised, the most deeply nested C<catch> handler is invoked. If this handler itself throws an error, the next most deeply nested handler is invoked with the new exception but the original stack trace. If the ...

When a C<catch> handler is called, not only is C<$@> set, but also a stack-trace string is passed in as the first argument. All frames will be listed in this stack-trace, starting with the most deeply nested frame.

If you want you can use simple frame names like C<"accepted"> but if you are recording error messages in a log you might find it useful to name your frames things like C<"accepted connection from $ip:$port at $time"> and C<"connecting to $host (timeo...

All frames you omit the name from will be shown as C<"ANONYMOUS FRAME"> in stack-traces.

Since multiple frames can be created within the same parent frame and therefore multiple child frames can be active at once, frames aren't necessarily arranged in terms of a stack. Really, the frame "stack" is more of a tree data structure (known in ...



=head1 "LOCAL" VARIABLES

In the same way that using C<frame_catch> or the C<catch> parameter to C<frame> preserves the dynamic environment of error handlers, the C<frame_local> function or C<local> parameter to C<frame> can be used to preserve the dynamic environment of loca...

Technically, perl's C<local> maintains the dynamic environment of B<bindings>. The distinction between variables and bindings is subtle but important. See, when a lexical binding is created, it is there "forever" -- or at least until it is no longer ...

However, with dynamic variables the same variable accessed in the same part of your code can refer to different bindings at different times. That's why they are called "dynamic" and lexical variables are sometimes called "static".



( run in 0.274 second using v1.01-cache-2.11-cpan-0d8aa00de5b )