http://qs1969.pair.com?node_id=608557

sulfericacid has asked for the wisdom of the Perl Monks concerning the following question:

While coding something today I came across an interesting question regarding coding styles. Say you have a test you need done in which, when successful/unsuccessful, you exit the script completely AND after that test is done, you do something else.

Easier asked with an example, I s'pose.

my $name = param("name"); if ($name eq "") { print qq(Sorry, name can't be empty); exit; } print "Thank you, $name. Your submission is complete.";
How many of you exclude the else clause in the above situation?
if ($name eq "") { print qq(Sorry, name can't be empty); exit; } else { print "Thank you, $name. Your submission is complete."; }
Can anyone think of a reason why the first example could be a bad idea under given circumstances? I can't see how either would be better or worse, but am curious to see how you guys would perform simple tests like this.


"Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

sulfericacid

Replies are listed 'Best First'.
Re: Coding styles using if/else
by kyle (Abbot) on Apr 06, 2007 at 01:41 UTC

    If I'm validating input, as in the example, I'm inclined to leave off the else. That's normally at the top of a sub, and I don't want to have the whole sub another level deep because it's all in else.

    If it's more like a real branch, I might include the else. If the behavior changes so that the one branch does not exit, I want to be able to do that easily (i.e., without having to add the else).

    I avoid using ternary operators for branching like this. I think of it as something that returns a value, so I don't like having it in a void context. If it's that important to save vertical space, I'd rather crowd my curlies than use a ternary.

    if ( ! $sanity ) { print "Mandatory happiness violated.\n"; exit } else { print "You are happy.\n" }

    ...but even that I don't like much.

    I'm generally of the opinion that code grows. Today's exit may be tomorrow's warn. The one line will be three. You should write it now to accommodate its growth later.

Re: Coding styles using if/else
by rhesa (Vicar) on Apr 05, 2007 at 23:11 UTC
    I use that pattern all the time. When I'm validating input, I want to bail out at the first sign of trouble. Once all input passes scrutiny, I continue with business. No need for an else clause in that case.
Re: Coding styles using if/else
by superfrink (Curate) on Apr 06, 2007 at 06:50 UTC
    I used to work at a company that had a policy of using the first method. ie of leaving off the else. (They did code reviews.) It was claimed that this lead to more "linear" flow rather than deeply nested flow.

    The idea is that the example if block is checking for (and dealing with) an exceptional situation. That check/deal step is a logical unit with respect to whatever the code it is part of is trying to accomplish.

    Once that check/deal step is done the program continues on with the next step. Including an else clutters the code and slightly hides the main focus of the code.

    Another effect of using else where it is not needed is it increases the level of nesting. That often makes code harder to understand.

    The company also had commenting standards so the code might look something like the following. GOAL means "something we want to do". CLAIM means "something that is true at this point in the code".
    my $name = param("name"); # GOAL : ensure input values are valid if ($name eq "") { print qq(Sorry, name can't be empty); exit; } # CLAIM : all input values are valid # GOAL : process input values print "Thank you, $name. Your submission is complete.";
      superfrink:

      And that blank area between the CLAIM and GOAL is the perfect location for:

      # CLAIM: all input values are valid assert($name ne ""); # GOAL: process input values
      (Yes, the exit above moots the assert in this case, but not all functions check all arguments.)

      ...roboticus

Re: Coding styles using if/else
by gloryhack (Deacon) on Apr 06, 2007 at 01:43 UTC
    I tend to use else (in these kinds of very simple cases) when the block before it occupies much in the way of vertical space in the editor window, but often exclude it when the preceding block is brief. That way the intent is obvious even when the introductory if() clause is scrolled off of the top of the editor window. If I was doing that test, it'd be:

    my $name = param('name'); if (defined $name && length $name) { # I prefer to test for the pass case rather than the fail. print "Thank you, $name, your submission is complete.\n"; } else { print "Sorry, name can't be empty.\n"; } exit;

    Your two examples and mine are all functionally equivalent, so it's just a matter of how the author likes to see things done. No worries.

    Edit for clarity: I also tend to minimize the use of exit and/or die whenever possible, which is why I included the else in my example. I use length in case the user's name is 0e0 or some such nonsense.

      That way the intent is obvious even when the introductory if() clause is scrolled off of the top of the editor window

      For a counterpoint, from the same line of reasoning, I drew the opposite conclusion.

      I put the shortest block in the if part, and the longer block in the else part, so the introductory clause is still visible in the editor window when you're reviewing the second part of the conditional. It becomes easy to say "yes, I'm here because that conditional just up there evaluated to false", because you can see it.

      If both sections are so long as to not fit in the window, I'll probably wind up breaking them both out into separate subroutines, because, by definition, they're doing an awful lot of stuff.

      Getting back to the OP, I'm a big fan of early returns, as it keeps the code closer to the left hand side of the screen. I'm a bit more leery of early exits. I dislike when some deeply buried routine decides it's time to stop the show (although END blocks can alleviate the problem of tidying up database connections and so on).

      • another intruder with the mooring in the heart of the Perl

          I put the shortest block in the if part, and the longer block in the else part, so the introductory clause is still visible in the editor window when you're reviewing the second part of the conditional. It becomes easy to say "yes, I'm here because that conditional just up there evaluated to false", because you can see it.

        Interesting.

        I just make sure the conditional as clear as possible, so I'll have if ( SomeCondition) { .. or unless ( SomeCondition ) { ..; then the blocks follow logically after that.

        Under your guideline, my code

        if ( SomeCondition ) { $this = 'that'; $foo = 'bar; $quux{'quaz'} = [ $this, $that ]; # More code follows .. } else { $this = 'the other'; }

        would be rewritten as

        if ( !SomeCondition ) { $this = 'the other'; } else { $this = 'that'; $foo = 'bar; $quux{'quaz'} = [ $this, $that ]; # More code follows .. }

        I find that harder to read, because I would need to take the condition, reverse it, and then follow what's going on in the first block. For the second block, I'd have to go back to the original, un-reversed condition.

        It's just not the way my brain works. ;)

        Alex / talexb / Toronto

        "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

        I put the shortest block in the if part, and the longer block in the else part, so the introductory clause is still visible in the editor window when you're reviewing the second part of the conditional.

        I try to do that too. I recall reading this guideline in a book about C ages ago. I don't adhere to it strictly, but if what I'm writing makes sense either way, I'll try to keep else as close to if as possible.

      gloryhack's code looks a lot better to me. What I have to add: whenever there is some code that may or may not be executed, I want that to be clearly expressed in the code. Code in a block expresses that this code is subject to flow control. Djikstra said "although the programmer only makes programs, the true subject matter of his trade are the possible computations evoked by them"-- any time my code can clearly show the reader the possible computations, I will gladly take the trouble to add an else or another level of indentation. Functionally equivalent, yes, but to me as a programmer, this seems much better.
      ~dewey
Re: Coding styles using if/else
by shigetsu (Hermit) on Apr 05, 2007 at 22:30 UTC

    Personally, I think it could be somehow a pathological case such as an implicit return from a sub, assuming you're just trying to avoid having following code executed; the exit; statement is fine though, if you explicitly want to exit. In former case, it works well, as long as you don't change anything - but, all of a sudden, it may break if you do (possibly triggered by removing/commenting the exit; statement accidentally).

    As a side note:

    If you're worried about the total size of the if {} else {} clause, you could give the ternary conditional operator (?:) a try (assuming your code doesn't continue below the ternary operator statement in this peculiar case):

    ($name eq "") ? print q{Sorry, name can't be empty} : print "Thank you, $name. Your submission is complete.";

      If you're worried about the total size of the if {} else {} clause, you could give the ternary conditional operator (?:) a try (assuming your code doesn't continue below the ternary operator statement in this peculiar case):
      ($name eq "") ? print q{Sorry, name can't be empty} : print "Thank you, $name. Your submission is complete.";

      (Sorry to reply so late but) this looks very wrong to me: the ternary operator is designed to operate on values, not to use it as a general purpose branching tool for its side effects. I would never do so except in golf: in particular the above example becomes perfectly fine if you amend it by factoring out the print:

      print +($name eq "") ? q{Sorry, name can't be empty} : "Thank you, $name. Your submission is complete.";
Re: Coding styles using if/else
by zer (Deacon) on Apr 05, 2007 at 22:51 UTC
    just dont get too carried away. Ternary operators turn bad really quickly
    you should take a look at perl best practices, it may say something on this
    $ARGV[0]?print "Thank you, $ARGV[0]. Your submission is complete.":do{ +print "Sorry, name can't be empty";exit;};
Re: Coding styles using if/else
by EvanCarroll (Chaplain) on Apr 05, 2007 at 22:49 UTC
    I think this is still not as good style as it could be, personally I don't like if/else for debugging as it apears convoluted to me, I would think this would be better:
    exit "Sorry, name can't be empty" if $name eq '' ; print "Thank you, $name. Your submission is complete.";
    IMHO printing for an error message is bad practice, let a function or a module take care of it, and exit (or better yet die, or croak) with a code or a message.

    UPDATE
    I didn't know exit() was CORE:: -- news to me. use die instead as said below, I thought this was a user func.



    Evan Carroll
    www.EvanCarroll.com
      You wrote
      I would think this would be better:
      exit "Sorry, name can't be empty" if $name eq '' ;

      It's not, as per perldoc -f exit

      exit EXPR
      exit Evaluates EXPR and exits immediately with that value. Example:
      ...

      Your code does exit 0 if $name eq '' which may or may not be what is intended, but what looks like a message being printed - isn't. Try at your shell

      perl -e 'exit "foo"'; echo $?

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        For this kind of usage, with an error message, he should use die instead of exit.