* Geoffrey Broadwell <ge...@broadwell.org> [2009-01-01 21:40]:
> In the below Perl 5 code, I refactored to pull the two halves of the PID
> file handling out of init_server(), but to do so, I had to return a sub
> from pid_file_handler() that acted as a "continuation".  The syntax is a
> bit ugly, though.  Is there a cleaner way to this in Perl 6?
>
> ######
> sub init_server {
>     my %options  = @_;
>
>     # ...
>
>     # Do top (pre-daemonize) portion of PID file handling.
>     my $handler = pid_file_handler($options{pid_file});
>
>     # Detach from parent session and get to clean state.
>     become_daemon();
>
>     # Do bottom (post-daemonize) portion of PID file handling.
>     $handler->();
>
>     # ...
> }
>
> sub pid_file_handler {
>     # Do top half (pre-daemonize) PID file handling ...
>     my $filename = shift;
>     my $basename = lc $BRAND;
>     my $PID_FILE = $filename || "$PID_FILE_DIR/$basename.pid";
>     my $pid_file = open_pid_file($PID_FILE);
>
>     # ... and return a "continuation" on the bottom half (post-daemonize).
>     return sub {
>         $MASTER_PID  =  $$;
>         print $pid_file $$;
>         close $pid_file;
>     };
> }
> ######
>
> When I asked this question on #perl6, pmurias suggested using
> gather/take syntax, but that didn't feel right to me either --

> it's contrived in a similar way to using a one-off closure.

Contrived how? I always found implicit continuations distasteful
in the same way that `each` and the boolean flip-flop are bad in
Perl 5: because they tie program state to a location in the code.
When there is state, it should be passed around explicitly. So I
think the return-a-closure solution is actually ideal.

F.ex. it keeps you entirely clear of the troublesome question of
when a subsequent call should restart the sub from the beginning
or resume it – should that happen when identical arguments are
passed? Or when no arguments are passed? Are there any rules
about the proximity of the calls in the code? Or does the
coroutine state effectively become global state (like with `each`
and `pos` in Perl 5)?

When you have an explicit entity representing the continuation,
all of these questions resolve themselves in at once: all calls
to the original routine create a new continuation, and all calls
via the state object are resumptions. There is no ambiguity or
subtlety to think about.

So from the perspective of the caller, I consider the “one-off”
closure ideal: the first call yields an object that can be used
to resume the call.

However, I agree that having to use an extra block inside the
routine and return it explicity is suboptimal. It would be nice
if there was a `yield` keyword that not only threw a resumable
exception, but also closed over the exception object in a
function that, when called, resumes the original function.

That way, you get this combination:

    sub pid_file_handler ( $filename ) {
        # ... top half ...
        yield;
        # ... bottom half ...
    }

    sub init_server {
        # ...
        my $write_pid = pid_file_handler( $options<pid_file> );
        become_daemon();
        $write_pid();
        # ...
    }

Regards,
-- 
Aristotle Pagaltzis // <http://plasmasturm.org/>

Reply via email to