Feeds:
Posts
Comments

Archive for December, 2010

Why Would I Ditch Perl?

A perl programmer asks why ditch perl? on the Perl Reddit. I briefly considered alternatives in my Is Perl My Perfect Compromise post. 18 months later there is a clearer answer:

Of the “big three general purpose scripting languages”, Perl is improving most quickly, has the best libraries and the most jobs available. There is no compelling reason to switch to Python or Ruby and plenty of good reasons to stay with Perl.

At my job Perl is one of the sanctioned languages and it makes work fun. Over the past 18 months, improvements have been coming thick and fast (go go Moose and regular release cycles). For Windows development Strawberry Perl is getting better and better.

Outside of web development CPAN is better than the Python and Ruby equivalents and Python has inferior scoping anyway.

None of the minority languages mentioned in my previous post such as Clojure, Scheme and Haskell have gained any traction so there is no need to discuss them further here.

Read Full Post »

Revisiting Autovivification

Last time I spoke about wrapping hash access I got a bit more than I bargained for. It’s still something I’m tempted to do from time to time.

Autovivification by default is very sensible (or perhaps Perl just suits me). When I set a parameter within a structure, I generally want all the ancestors to be created first. That’s why I have the following aliases to mkdir.

jared@localhost $ alias | grep mkdir
alias failingmkdir='/bin/mkdir'
alias mkdir='mkdir -p'

Autovivification on data retrieval though, can be a bit confusing.

use strict;

my $data = {};
print '1:', exists($data->{'key1'}), "\n";
if (! exists($data->{'key1'}{'key2'})) {
    print '2:', exists($data->{'key1'}), "\n";
}
jared@localhost $ perl5.10 t.pl
1:
2:1

The CPAN Autovivification Module

Fortunately, it’s easy enough to disable it with the autovivification module.

no autovivification qw(strict fetch exists delete);
perl t.pl
1:
Reference vivification forbidden at t.pl line 7.

Promote Uninitialized Warnings to Fatal

Zoul mentions a way to avoid typical autovivification errors1 on stackoverflow.

use warnings NONFATAL => 'all', FATAL => 'uninitialized';

Or unlock_keys and lock_keys_plus from Hash::Util mentioned by Chas. Owens in the comments might be closer to what is needed in some circumstances.


1. True, it doesn’t only apply to autovivification, but the other effects are useful too.

Read Full Post »

For the producer demonstrated last time, it is easy to make a consumer using AnyEvent. Not only that, I can borrow most of the code from my list_processes script.

The utility functions are the same as in the unix pipe producer/consumer.

sub consumer
{
    my ($host, $port, $cb) = @_;

    my $cv = AE::cv();

    my $handle; $handle = AnyEvent::Handle->new(
        connect  => [$host => $port],
        on_error => sub {
            print("Connection error: $!\n");
            $handle->destroy();
        },
        on_eof => sub {
            print "Connection closed\n";
            $handle->destroy();
            $cv->send();
        }
    );

    # We need to consume the first line which contains the PID message
    $handle->push_read(line => sub {});

    $handle->on_read(sub {
        my $handle = shift;
        my $data = $handle->rbuf();
        $handle->rbuf() = '';
        $data =~ tr/\r//d;
        foreach my $line (split /\n/, $data) {
            $cb->($line);
        }
    });

    return $cv;
}

The callback function checks the subject is correct and then calls process_file(...). It should be fairly easy to see how to extend this for much more complex producers and consumers.

sub process_file
{
    my $file = shift;
    my_log "Processing file [$file]";
    # File processing logic here ...
}

sub handle_line
{
    my $line = shift;

    my ($subject, $action) = split /\s+/, $line;
    if ($subject =~ m{^/producer/file-creator/new-file}) {
        process_file($action);
    } else {
        my_log "FROM PRODUCER [$line]";
    }
}

my $cv = consumer('localhost', 12345, \&handle_line);
$cv->recv();

Read Full Post »

Previously we looked at connecting one producer to one consumer using a unix pipe. If we want to do many to many connections, we can use the AnyEvent Notifier I mentioned in Connecting Software Systems.

Instead of echoing a notification that a work unit has been created to STDOUT I write it to a socket connected to the notifier.

IO::Socket makes this absurdly easy.

use IO::Socket ':crlf';
use constant SHUTDOWN_SOCK_RW => 2;

my $sock = IO::Socket::INET->new(PeerAddr => 'localhost:12345');

for (1..5) {
    my_log "Iteration $_";
    my $filename = create_file($top);
    print $sock "/producer/file-creator/new-file $filename" . CRLF;
    my_log "PRODUCED $filename";
}

$sock->shutdown(SHUTDOWN_SOCK_RW);
$sock->close();

I often use a subject<SPACE>message format to make it easy for clients to filter between important messages.

I’ll demonstrate the consumer next time.

Read Full Post »

Follow

Get every new post delivered to your Inbox.