* 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/>