Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

A new idiom -or- I Hate Unless

by erikharrison (Deacon)
on Aug 22, 2004 at 20:59 UTC ( [id://384970]=perlmeditation: print w/replies, xml ) Need Help??

I hate unless.

I have code like this:

unless (unlink $file) { carp "Couldn't remove file $file!\n"; ... ... }

There are two problems with this. First, that block goes on for about 10 lines, but it's mostly about handling an error condition - I'd rather it not distract from the flow of the code. Second, that unlink should make you sit up and notice. But it gets tucked inside the parens, and doesn't get enough attention. We could put it the success/fail in a temp var, which does make the unlink a little more noticable, but at the expense of an extra var, and a little excessive verbosity (I crime I commit already in speech ;-).

unless tends to guard error conditions I find. This always trips me up, especially when rereading my own code, since I tend to skim stuff I wrote. I either skip the unless because I know it's error handling, or get halfway through the block and go "Wait a minute" and scroll back up to reorient myself. I started using ifs on negated conditions, but that unary not is even more invisible when wrapped in parens.

If I push the error handling into a sub or function somwhere, this is pretty ideal:

do_error($file) unless unlink $file;

as the function name makes it good and self documenting, and it doesn't interrupt the flow when I'm digging around.

But now I've picked up maintainance on a bunch of code that has been growing both in terms of quantity and quality over the last 5 years. Because of the design of the code (not to mention my deadlines) refactoring the error code out into a seperate function really isn't possible, and the code has a tendency to blend unreadable line noise with hiding important action in obscured places. This is the idiom I came up with to keep myself sane.

unlink $file or do { #copy and paste of old code };

It's simple, it's readable, and it puts the scary unlink out there at the beginning of the line. My only problem with it is I got tripped up by the semicolon the first couple of times. I've managed to purge most of the more frusterating unlesses from my new code, and I think readablity improves considerably. Does any one else use this idiom? If you had to maintian my code later would this bother you? What other tricks have people come up with to keep the code oriented on the main action as opposed to exceptions?

Cheers,
Erik

Light a man a fire, he's warm for a day. Catch a man on fire, and he's warm for the rest of his life. - Terry Pratchet

Replies are listed 'Best First'.
Re: A new idiom -or- I Hate Unless
by Zaxo (Archbishop) on Aug 22, 2004 at 21:24 UTC

    Both your reordering to place the meat of the statement first, and the use of the or operator in error conditions, are covered in perlstyle. You've chosen well, imo.

    Perhaps you will get to a stage of maintainance that you can begin refactoring. Pasted blocks are a prime place to look when you do. A stock comment like '# Factor Fodder' or '# Pasted' will help identify them when that time comes.

    Don't blame unless. It's a fine operator, just not the best choice for that statement.

    After Compline,
    Zaxo

      My problem is not so much unless as the problem it tries to fix - namely making doing something when a condition is false readable and clear. It does that, to an extent. But in 90% of the cases the code is for handling an error.

      Marking cut and paste code as such is a great idea. The code needs some documentation anyway. It's all uncommented.

      update: fixed typo
      Cheers,
      Erik

      Light a man a fire, he's warm for a day. Catch a man on fire, and he's warm for the rest of his life. - Terry Pratchet

Re: A new idiom -or- I Hate Unless
by cLive ;-) (Prior) on Aug 22, 2004 at 21:34 UTC

    Because of the design of the code (not to mention my deadlines) refactoring the error code out into a seperate function really isn't possible

    Maybe I'm missing something here but, if you're already rewriting these error handling cases to make them more readable, how much more work would it be really to add a sub/module to handle the errors?

    You can have the added benefit of working on how to deal with errors more comprehensively over time. For example, here's a snippet of our "fatal error" method under mod_perl (not everything, just the interesting bit, and rewritten to run standalone rather then using some internal methods we use).

    sub fatal_error { my $err = $_[0]; my @caller = (); my $i=-1; while ( caller(++$i) ) { (caller($i))[1] =~ /5\.8\.0/ and last; # don't log apache mod +in trace push @caller, sprintf("-> %s at line %s\n", (caller($i))[1,2]) +; } open(LOG,">>/path/to/err_log") or die $!; print LOG `date`,"$err\n",@caller,"\n"; close(LOG); # display fatal error page, since this is in a web environment }

    Like I said, this is just a snippet, leaving out the emailing of the error to me, the logging in the local DB, and the centralised logging for later analysis.

    If you start refactoring as you go, you'll have much better control over how errors are dealt with and, when you get an idea on improvement, you can easily add it in.

    Yes, deadlines are there, but by not factoring refactoring (intended :) into your time lines, you're creating more work down the line.

    If convincing the powers that be of the wisdom of this is problematic, buy your boss a copy of Peopleware, make them read it, then schedule a time where you can discuss the issues it brings up, and how you can implement them to make your work more productive.

    Saving time now by ignoring problems is a false economy.

    .02

    cLive ;-)

    ps - oh, and I'd call it like this:

    unlink $file or fatal_error("Couldn't delete $file: $!);

      You're completely right of course. The issue with not refactoring is that every error condition is slightly (or, in a few cases, vastly) different. The deadlines are on the order of hours, not days or weeks, and it'll take some thought on how to reorganize the code so that these slight variations can be handled from a few functions. It's not so much fail-and-log or fail-and-die. This is "fail and connect to different db to pull out sensible defaults for unset fields in existing database but only if called in a certain context".

      In other words a nightmare. But your point stands that if I can refactor now, the extra ten minutes is probably worth it.

      Cheers,
      Erik

      Light a man a fire, he's warm for a day. Catch a man on fire, and he's warm for the rest of his life. - Terry Pratchet

      janitored by ybiC: Replaced "run-on phrase using dashes" with balanced quotes and italics, for to avoid lateral scrolling

Re: A new idiom -or- I Hate Unless
by Mr. Muskrat (Canon) on Aug 22, 2004 at 22:08 UTC

    I try to use the following style:

    unlink $file or do_error($file);

    It puts the important part out front and doesn't interrupt the flow. You can skip past the gory details of the error handling if you don't need to read about it.

Re: A new idiom -or- I Hate Unless
by grinder (Bishop) on Aug 22, 2004 at 22:36 UTC

    Hear, hear. As a statement modifier I have no problem with unless, but I cringe when I see it used as the block form. I find it interesting to note that perlsyn doesn't even bother mentioning it, so I'm surprised that it pops up so often.

    The main reason for my dislike is the puzzlement factor that a newcomer to Perl will have when encountering the statement. It's obvious to me, because I'm familiar with Perl, but I can also see that someone coming from another language could have considerable difficulty realising that unless is the opposite of if. I can imagine such a person wondering if there isn't some subtle distinction if using it instead of simply negating the if. So for me it falls into the Too Clever For Its Own Good category. Doubly so when the code becomes unless( $cond ) {...} else {...}. That's just perverse.

    My own approach to avoiding block unless statements is to simply use if( not $cond ) {...}. Works for me.

    My main rule is to arrange to have the if part be the shortest, and the else part the longest, so that at the beginning of the else it's easy to see the conditional that led you here. Locality is more important.

    - another intruder with the mooring of the heat of the Perl

      The main reason for my dislike is the puzzlement factor that a newcomer to Perl will have when encountering the statement.

      Why should that be a concern? Do you use sequential alphanumeric identifiers for variables and subroutines to avoid the puzzlement that newcomers to English will have when encountering idiomatic words?

      I agree with you about avoiding unless {} else {}, but that's because it's confusing to native English speakers as well. I don't believe that avoiding idioms -- where they'd otherwise be appropraite -- in deference to hypothetical unexperienced maintenance programmers is a good idea.

      Update: I misread the parent post the first time, with which I agree. Sorry about that.

        I agree with you about avoiding unless {} else {}, but that's because it's confusing to native English speakers as well.
        Is it? I'm not native (Russian) and the whole concept of unless is alien to me. But I got over it, and even got used to it and even became fond of it (due to Perl) :) Never thought that unless {} else {} does not look like real English. Thanks for education!

      Anyway, I still think unless is still much nicer than its slang equivalent, !if .

      I have no problem with unless, but I cringe when I see it used as the block form. I find it interesting to note that perlsyn doesn't even bother mentioning it, so I'm surprised that it pops up so often.

      It is mentioned in perlsyn (5.8.2), it's just easy to miss it:

      from perlsyn(1): The following compound statements may be used to control flow: if (EXPR) BLOCK if (EXPR) BLOCK else BLOCK if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK ... The "if" statement is straightforward. Because BLOCKs are alwa +ys bounded by curly brackets, there is never any ambiguity about which "if" an "els +e" goes with. If you use "unless" in place of "if", the sense of the test is rev +ersed.

      Btw, why isn't there an elsunless statement like if : unless = while : until = elsif : elsunless?

      (Update: fixed /code tag)

        Btw, why isn't there an elsunless statement like if : unless = while : until = elsif : elsunless?

        LW had something to say on that in a recent post on p6lang:

        .... And there's a new C<elsunless> in Perl 6--except that it's spelled C<elsif not>. C<:-)>

        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: A new idiom -or- I Hate Unless
by Your Mother (Archbishop) on Aug 23, 2004 at 01:14 UTC

    I agree there are times when its use can make things confusing but unless is a very natural language modifier. As such, I love it. It lets me think in perl.

    unless ( $me->is_tired ) { $me->go_to_the_market(); } # the other direction, to me, reads perfectly well $me->go_to_the_market() unless $me->is_tired();
Re: A new idiom -or- I Hate Unless
by Juerd (Abbot) on Aug 23, 2004 at 09:09 UTC

    I agree. I always try to write error handlers using "or". Preferably with "or die", but "or do" isn't a problem. But it is certainly not now. I have been doing this for just over a year now, but I have copied it from someone else.

    In my style guide is:

    Error checking is done using or. This means open or do { ... } instead of unless (open) { ... } when handling the error is more than a simple statement.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re: A new idiom -or- I Hate Unless
by Aristotle (Chancellor) on Aug 23, 2004 at 10:50 UTC

    As it has been mentioned, this isn't a new idiom at all. We have forever been saying open $fh, $mode, $file or die "Can't open $file: $!", and of course, that same approach generalizes to any kind of error handling.

    This is one of the facets of Perl's adherence to linguistic principles. (I think Larry mentions that in his essay about the subject.) It tries to let the programmer arrange expressions in whichever way he deems necessary to stress the really important part. That's why we have the statement modifiers, for example. next if $long_and_complex_conditional_here is a familiar and beloved sight in Perl code; I often cringe when I'm in C world and have to arrange the same thing the other way around.

    That is no particular reason to hate unless, of course. if vs unless is just another of these facets: it lets you build expectations appropriately. I use unless when I expect that the condition will only rarely be true. For me, if not is an indication that the condition will tend to go either way, or even be true more often than not — the opposite of the same thing expressed with unless.

    Makeshifts last the longest.

Re: A new idiom -or- I Hate Unless
by ambrus (Abbot) on Aug 23, 2004 at 08:44 UTC

    About how I use conditionals?

    In perl I mostly use and and or for conditionals much more often than if and unless.

    I never use prefix unless. I very rarely use postfix unless, only in cases when the condition almost always holds, like print ", " unless $index==$length-1;

    I use prefix if for conditionals that have both a then and an else (or elsif) branch. I sometimes use prefix if for other conditionals randomly, especially when there is no action done in the condition. I sometimes use postfix if in similar cases, when the condition is not very important.

    But for most conditionals, I just use and, or, or with multiple statements and do {, or do {. That is good because it places emphasis on the condition.

    This is only my coding style in perl, it's of course different in other languages as their conditional constructs are different too.

Re: A new idiom -or- I Hate Unless
by YuckFoo (Abbot) on Aug 23, 2004 at 17:30 UTC
    unless always reminds of the M*A*S*H episode where a bomb lands in camp unexploded. Hawkeye(?) and Radar(?) attempt to diffuse it. It's the old 'which wire to cut first' routine. Radar is reading the defuse instructions to Hawkeye:

    Cut the red wire...

    *SNIP*

    ...but first cut the blue wire.

    And hilarity ensues. Unless I am trying to write Perl comedy, I have no use for it.

    do_it() or do { something_else(); will_do_fine(); };

    YuckLess

      I remember seeing the same joke (more or less) in King of Queens. Arthur is reading a phone number aloud one digit at a time, and Doug is dialing it.

      A: Two,
      D: (dials)
      A: three,
      D: (dials)
      A: nine,
      D: (dials)
      A: six,
      D: (dials)
      A: -teen...

      I should have known it had a long history.

      Re: Perl's "unless", I use it very rarely, and only in the postfix form.

      I believe it was Hawkeye and Trapper who tried to defuse the propaganda bomb. I think it was colonel Blake who read, with Radar right next to him (as usual). But I'm not quite sure.

      ihb

      Read argumentation in its context!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://384970]
Approved by Zaxo
Front-paged by Zed_Lopez
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (9)
As of 2024-03-28 10:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found