April 04, 2007

A couple of the things I miss most from perl...

At this point in my career I'm probably 50/50 in the time I've spent using Java and Perl. When I first got into Java my brain tried to map Perlisms to Java, but I think I'm now fluent to the same degree in each.

That said, even after six years of doing Java FT there are still some things from Perl I dearly miss, and they break down into syntax and constructs.

Syntax: And I've said many times that, barring extreme cases, disliking a language because of its syntax is like disliking a spoken language because of a dialect. After a while of reading or hearing it, you get acclimated. What was once jarring becomes the norm.

That said, the things I miss most are next, last, and unless. The first two are just lingo preferences both: next and last are more humane (and informational) than their equivalents, continue, and break. (Seeing 'break' in a program is still occasionally funny, as if you're attempting to induce a random bug with a single verb.)

But unless is different. One of my pet peeves with Java libraries is that there's never an 'isNot' for every 'is' property. So you wind up mixing metaphors, using a terse negation operator with a verbose boolean property invoked as a method. For example, if I wanted to process a list only if it had data, I'd do:

List thingies = getThingies();
if ( ! thingies.isEmpty() ) {
   // do stuff with thingies
}

Besides the mixing metaphors, there's more of a logistical problem (and source of a future rant): with most developers' weird whitespace preferences, the negation becomes very difficult to see because it's rendered as:

List thingies = getThingies();
if (!thingies.isEmpty()) {
   // do stuff with thingies
}

Putting the negation in the method is better, either as:

List thingies = getThingies();
if (thingies.isNotEmpty()) {
   // do stuff with thingies
}

or you can have a more readable positive version, which suffers because it's not a valid JavaBean property and therefore either un- or differently-usable by lots of tools and libraries:

List thingies = getThingies();
if (thingies.hasItems()) {
   // do stuff with thingies
}

Both of these move the negation right, into the property. Perl moves it left, into the condition declaration:

# assume that $thingies is a list object with methods
my $thingies = get_thingies();
unless ($thingies->is_empty()) {
   // do stuff with thingies
}

But that's just the beginning. Where it really shines is with prefix operations in loops where you want to skip items, or stop iterating entirely. To take an example from my daily work, say you have a plan of care for a nursing home resident and you want to only use that plan if the resident is not 'on leave' (out of the home) or discharged. In Java, this might look like:

Listlt;Plan> plans = getPlans();
for ( Plan plan : plans ) {
    if ( plan.getResident().isNotActive() ) {
        continue;
    }
    ...

(Note that a nice object designer put the negative condition as a method!)

I could have put the 'continue' at the end of the line, eliminating the braces, but then it gets lost. Perl gets around this by putting it at the front, so you have:

my @plans = get_plans();
foreach my $plan ( @plans ) {
    next unless ( $plan->resident()->is_active() );
    ...

Reducing the number of lines (from 3 to 1) is secondary to making your intent much clearer, and that's what I dearly miss. One of the 'features' built-in to Perl (and its culture) is TMTOWTDI. It makes non-regular Perl users frustrated, but IMO it can actually make for much more readable programs because your intent can be more clearly stated.

Constructs: The other two items, grep and map are kissing cousins, and represent the ability to do something on a bunch of stuff (an Iterable, in Java terms). That something might be to conditionally include it into another bunch of stuff, or to pull common data out of each of the bunch, or whatever.

There are libraries that kinda-sorta do this (like commons collections or jga), but they're clunky as hell. It's not necessarily their fault, in many cases Java makes this necessary. But the result is the same: the clunkiness discourages the sort of active use that, again, expresses intent much more clearly. For instance, say I wanted to pull out the ID from every resident given the list of plans above. I could do it the long way:

List<Integer> residentIDs = new ArrayList();
for ( Plan plan : getPlans() ) {
    residentIDs.add( plan.getResident().getID() );
}
</pre>

whereas in Perl, it might be:

my @residentIDs = map { $_->resident()->id() } get_plans();

To the uninitiated, map is scary, using the infamous $_ that non-Perl folks seem to instinctively hate at first sight. I always tell them, "Just substitute 'it' where you see dollar-underscore." So your block now reads "get the resident from it, then get the ID from the resident and return that." Not so scary, and after you see it and use it a few times it's second nature -- you get acclimated.

Next: PittJUG: JavaSpaces presentation
Previous: Our South Park characters