25 Oct 2009 fxn   » (Master)

Emulating Ruby Blocks in Perl

Ruby Blocks

Ruby blocks allow you to run code in the caller from within a method:


   # definition
   def twice
     yield 1
     yield 2
   end
 
   # example call
   twice do |n|
     puts "croak! (#{n})"
   end
 
   # output
   # croak! (1)
   # croak! (2)

In case you never saw something like that before, twice expects to be called with a block. That's the code between the do ... end keywords in the example call. Each call to yield runs the block in the caller. Arguments may be passed, in the example we pass a integer.

This is a powerful tool, Ruby is full of all sorts of internal iterators thanks to it:


    array.each_with_index do |item, i|
      # ...
    end

You can wrap/decorate chunks of code with them providing a very easy and intuitive usage. For example:


    File.open(filename) do |file|
      # ...
    end

opens a file, passes the filehandle to the block, and when the block is done it closes it.

Another example from my Rails Contributors application (simplified here):


    acquiring_sync_file do
      # ...
    end

The code within the block runs only if acquiring_sync_file could get a lock on some given sync file. If it could, once the block is done the lock is released.

Ruby Blocks in Perl

Perl does not have blocks like that, but you can emulate them in a way that may cover some use cases:


    acquiring_sync_file {
      # ...
    };

The trick comes from a feature of Perl that is not widely used: subroutine prototypes.

You may have noticed that some builtin Perl subroutines behave in a strange way. For example push:


    push @array, 5;

If push was an ordinary subroutine, it would receive the elements of @array and a 5 in @_, with no possible way to modify @array, which was lost by its evaluation in list context before the function call.

But push somehow is able to tell @array from the 5, and actually modify it. There's something special going on there. You can write you own subroutines like push and other thanks to subroutine prototypes. They are documented in perlsub.

Point is: if the first argument of a call is an anonymous subroutine, Perl forgives you the sub keyword if you set an appropriate prototype:


   sub twice(&) {
       my $coderef = shift;
       $coderef->(1);
       $coderef->(2);
   }
 
   # as if it said twice sub { ... }
   twice {
       my $i = shift;
       print "croak! ($i)\n";
   };

The rationale for that is to give you a way to write your own subroutines with map-like syntax. As you see, we can pass arguments as well.

Opening a file with automatic close would be:


   sub xopen(&@) { ... }
 
   xopen {
       my $fh = shift;
       # ...
   } $mode, $filename;

As you see xopen arguments would go after the anonymous subroutine, because this trick is only allowed if the coderef is the very first argument.

Drawbacks

The whole range of subroutine prototypes have a few gotchas, but what's specifically needed here works fine and some Ruby idioms can be emulated quite well. Subroutine prototypes do not work at all in methods though.

rubyisms

Simon Cozens' rubyisms Perl module provides a hackish yield so that you do not need to execute coderefs explicitly.

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!