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.

pmichaud offered several possibilities (I've converted some of his
suggestions expressed as prose into code, so the errors there are mine):

1. Take advantage of Perl 6 syntax reduction to turn 'return sub {...}'
   into 'return {...}' (or even just fall of the end with '{...}', I
   suppose).  This is visually slightly better, but still leaves the
   bottom half inside a block that merely exists to satisfy Perl, not
   actually representing anything intrinsic about the problem.

2. Throw a resumable exception in the middle:

   sub init_server {
       # ...
       pid_file_handler($options{pid_file});
       become_daemon();
       pid_file_handler();
       # ...
   }

   sub pid_file_handler {
       # ... top half ...
       throw ResumableException;
       # ... bottom half ...
   }

   He also suggested a variant syntax with an adverb on return:

   sub pid_file_handler {
       # ... top half ...
       return :resumable;
       # ... bottom half ...
   }

   I suggested a naked yield syntax:

   sub pid_file_handler {
       # ... top half ...
       yield;
       # ... bottom half ...
   }

   These all desugar to the same thing, of course.

3. Make become_daemon a part of pid_file_handler, or vice-versa.
   I rejected both of these on the basis of separating different
   things into different subs.  The two tasks are only tangentially
   related, and neither really seems like a subordinate op of the
   other.

4. In order to keep the sub separate, but still not split the
   pid_file_handler call, I came up with a variation of #3 in which
   pid_file_handler takes a callback parameter:

   sub init_server {
       # ...
       pid_file_handler($options{pid_file}, &become_daemon);
       # ...
   }

   sub pid_file_handler($pid_file, &callback) {
       # ... top half ...
       callback();
       # ... bottom half ...
   }

   That seems like a silly contortion to hide the problem, and
   doesn't represent my intent well -- the pid file handler doesn't
   need to send a message, it needs to yield control while waiting
   for something else to happen.

5. Make a new PidHandler class and address the problem in OO fashion:

   sub init_server {
       # ...
       my $pid_handler = PidHandler.new(file => $options{pid_file});
       $pid_handler.top();
       become_daemon();
       $pid_handler.bottom();
       #...
   }

   This is certainly workable, but again feels like a contrived
   workaround in the same way that gather/take and return {...} do.
   Plus, writing a new class and using OO/method call syntax just to
   allow a sub to be "split" seems like pointless busy work.  Not
   as bad in Perl 6 as in Perl 5, but still.

In the end, I think I like the 'naked yield' idea best of the ones we
have so far.  Any comments or other ideas? [1]


-'f

[1] Other than that I've used the word 'contrived' too many times.  :-)


Reply via email to