Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Re: Re^2: Pattern Matching Query

by PhiRatE (Monk)
on Sep 18, 2002 at 09:46 UTC ( [id://198779]=note: print w/replies, xml ) Need Help??


in reply to Re^2: Pattern Matching Query
in thread Pattern Matching Query

Actually what I did was introduce two guard clauses. I am aware that it was correct in either fashion, it is my preference to have drop-through rules of the manner displayed previously. I also prefer explicit "false" return, and if there was some way I could say "return false" and get the same effect as just "return" I'd be using it :) undef isn't a bad concept tho.

Those are simply elements of my style however, the reasoning behind guard clauses is obvious in larger functions, in this case it is superfluous but assuming a reasonably efficient action on the part of the interpreter I see no likely efficiency loss, so the consistency rule applies :)

The re-use of the $range var is nice however.

Replies are listed 'Best First'.
Re^4: Pattern Matching Query
by Aristotle (Chancellor) on Sep 18, 2002 at 17:46 UTC

    The problem with return 0 is that it's true - in list context. The only false list is the empty list and yours has one element.

    Your approach separates a single statement into three distinct ones and will execute that way too. There is in fact loss of efficiency associated with using blocks there. The interpreter cannot optimize anything in the first place, and if you meant compiler optimization, it won't salvage any efficiency because it's rather rudimentary even if it has a few clever tricks for some highly specific cases.

    And not only does it execute that way, it has to be read like that too, with far more brackets and keywords around to grok. Compare the plain-English translations:

    if an assertion fails abort the function, if a second assertion fails abort the function, if still here then return true
    vs
    return the combined success of assertion one and two

    You tell me which one is more fluidly readable. Remember - source code is only coincidentally machine interpretable, its main purpose is to be read by a programmer.

    Makeshifts last the longest.

      Ah. Interesting. Tell me then, which is more readable:

      if an assertion fails, return false.
      if an assertion fails, return false.
      if an assertion fails, return false.
      return true

      or

      return the combined success of assertion one and assertion two and assertion three

      Wait, lets try that again:

      if an assertion fails, return false.
      if an assertion fails, return false.
      if an assertion fails, return false.
      if an assertion fails, return false.
      if an assertion fails, return false.
      if an assertion fails, return false.
      return true

      vs:

      return the combined success of assertion one and assertion two and assertion three and assertion four and assertion five and assertion six

      Now I have little doubt this will prove to be debatable. In my opinion however, for humans, the first is easier to read, and more importantly, more consistant (WHAT! You say consistant? why is this consistant evl PhiRatE person! well, explainations shall be forthcoming).

      The concept I utilised is one known as a "Guard clause". It is, by my own admission, entirely overkill in the two and maybe in the three condition simple function that we're playing with now, however it becomes very important in more complex functions, and thus the principle of being consistant with your code suggests that (given no appreciable efficiency or readability loss) you should use it in simpler functions as well.

      The normal "best case" example for guard clauses is like this:

      function a ($fruit, $vegetable) { if (!$fruit) { return; } # Guard clause if ($vegetable) { print "Fruit and Vege"; } else { print "Just the fruit ma'am"; } }

      The idea being that arguments to the function and trivial tests are done immediately upon entry. The reasoning behind this is simple, it is easier to read nothing than it is to read anything, no matter how readable anything is. Thus, if you are tracking a bug through a series of functions, the earlier you encounter something that says "that condition is taken care of in this manner" the sooner you can stop reading that function and get back to finding the typo in line 700 of ObscureFoo.pm.

      As such, I maintain that, except in simple cases (such as the one we are really supposed to be talking about :) guard clauses are a superior method of laying out a set of "deny" rules as it were (or accept rules if your function suits it), rather than creating a stacked boolean expression. It also has the benefit of extending elegantly to multi-line operations and individual operations depending on exactly what failed (Too many items! Item not recognised!) without completely refactoring the expression (into guard clauses anyway). (If you wish an exercise to test this, take the function we were working on, and get it to throw an exception when there are too many items. In mine you can do it with one change, in yours, you must effectively write mine, then make the change.)

      So, while I agree that in the case specified, your example is marginally easier to read than mine, I maintain that my structure provides, overall, more consistency with the rest of the code likely to be written, and supports later modification with less issue.

      I agree that the primary purpose of source code is to be read by a programmer, but I also recall that the biggest cause of failure in source code is incorrect modification. It would seem to me then, that a very light cost in readability for the advantage of seamless and elegant modification is a win, as is a general consistency with other, similar but more complex operations elsewhere in the code.

      Of course, such things seem to be to some extent subjective. Interestingly I'm usually annoyed by this assertion since I believe very few things in programming are really as subjective as they are made out to be, however I have one particular aspect which "warps" my opinion of certian practices. I have a bloody awful memory :)

      Thus, any practice which means I need to read less code (in ops, not in lines or characters) and remember fewer things (contents of variables, meanings of obscurely named functions, constants) tends to weigh higher with me than with some other programmers I know.

      Guard clauses fall squarely into this category, with the amount of code read per debugging hunt being considerably reduced in the average case by the presence of negative assertions right at the start of each function.

      People with a better memory may see less benefit from this technique :)

        You comparison was unfair. Note my initial example used formatting for neither. The second case really should have been
        return the combined success
        of assertion one
        and assertion two
        and assertion three
        and assertion four
        and assertion five
        and assertion six

        If you're using formatting to line one up, you have to use formatting to line the other up as well. I think I can stop here, as far as this particular example is concerned..

        I have nothing against the concept of a guard clause per se, though your example would be much more readable if you emphasize what it is by putting the return in the spotlight and avoiding the ! linenoise:

        return unless $fruit;

        As far as bad memory is concerned, I don't see how my style requires a good one. To the contrary, actually, I tend to be very visually oriented. My code formatting follows that rule - I want to be able to glean the structure of a function's body without having to actually read and grok it all, and indentation carefully follows that motto. Functions should usually not be longer than about 25 lines. Some have to be of course, but those are few and far between. Most of mine tend to be around 15. That's so little you need no memory - you can take the entire function in in a single look. It's beneficial to have as little line noise as possible. Each statement should do as much as possible while being readable at a glance. Repetition is to be avoided. Contrary to intuition, spotting subtle differences in a repeated pattern is difficult - it's easy to detect their presence, but hard to actually make them out. (Have you ever seen much repetition in literature outside of poems?)

        Basically I try to write Perl close to how I'd write the same thing in English.

        Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://198779]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-03-19 02:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found