Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

A matter of style

by Ryszard (Priest)
on Feb 14, 2003 at 14:40 UTC ( [id://235275]=perlmeditation: print w/replies, xml ) Need Help??

When doing my coding i've noticed i'm checking and chucking the input to my methods before the real logic of the module, rather than using a complex set of if then elsif's.

For example:

sub doSomething { my $self = shift; my $q = $self->query(); return "Invalid Login!" if ($q->param('login') =~ /^[\w\/\-]{0,32} +$/); #main guts of routine here... return $outputOfRoutine; }

I'll use the same construct with die, or croak as appropriate..

This works quite well for me as I can put all the semantic validation at the top of the routine and worry about other integrity/logic later on in the routine.

I'll never return from the "middle" of a routine as i find it makes debugging a little more difficult as there are multiple "areas" where the routine can be exited from. Beside the semantic validation at the top of the routine the exit will always be at the bottom before the }

Purists say there should only be one entry and one exit and anything else is obfu. What do you say?

Replies are listed 'Best First'.
Re: A matter of style
by robartes (Priest) on Feb 14, 2003 at 14:52 UTC
    I do the same as you do. The convenience of doing parameter validation early on and bailing out early on is IMO that it binds parameter validation visually to the function (if that makes sense). When you're skimming over the function while reading the code, it's easy to see what parameters are expected and what their format and restrictions are.

    Also, I find that it helps me focus when I write a function: first, validate parameters, then worry about the algorithm / implementation / whatever without having to think about invalid parms.

    So, for the sake of self-documenting code, I'd put param validation at the top of the function. The added exit area is not so much of a problem, as you're still only exiting at the start or end, not in the guts of the routine.

    CU
    Robartes-

Re: A matter of style
by adrianh (Chancellor) on Feb 14, 2003 at 16:12 UTC
    Purists say there should only be one entry and one exit and anything else is obfu. What do you say?

    It's a common idiom in many languages - so common it's listed in Fowler's refactoring book (Replace Nested Conditional with Guard Clause.)

    It's a nice thick book - so you can always "re-educate" any purists you may find with it (apply swiftly to back of head :-)

Re: A matter of style
by jdporter (Paladin) on Feb 14, 2003 at 18:29 UTC
    I'll never return from the "middle" of a routine...
    I disagree with that philosophy 100%.

    Routine entry and routine exit are not, as some think, symmetric.
    That is why computer languages have GOTO but not COMEFROM (with the exception of Intercal, but that's a joke).

    Early return from a subroutine is like short-circuiting logic - which, we all can agree, is a Good Thing.

    jdporter
    The 6th Rule of Perl Club is -- There is no Rule #6.

Re: A matter of style
by hardburn (Abbot) on Feb 14, 2003 at 15:23 UTC

    I never liked programming purists. I'll use OO when it suits me, not because everyone else is doing it. I don't need to expand my 50-line Perl script into 300 lines just to support OO. Shouldn't use ASM? Ha! I'll do it just to spite you (in my free time, of course--I've got things to do at work :). No, I'm not going to put a # end of foo subroutine or some such over-documentation after every end brace. Format your code correctly and you don't need to.

    In short, the purists are blinded by "correctness" and let it get in the way of doing the job.

    ----
    Invent a rounder wheel.

      I hear where you are coming from here, but I find some idioms to very helpful, such as the comment ending a closure. Not so much because I have to, but because I like to. It comes in very handy for me to quickly extend a given sub routine/method, if I can (in vi)
      /# END sub blah

      That being said, I don't do it because it is part of nomenclature to do it that way, I do it because that is my style, and it makes me more efficient when coding. Granted there are always people who follow a particular mindset/way of doing something because then they dont have to think, but there are also times when people who walked the same "path"/encountered the same problems (large code base, poorly written code) and have managed to find resonable solutions to those problems, and disseminated that info. I always question what is given to me, but sometimes their reasoning makes sense. On the other hand, there was a thread not too long ago about the idiom
      $self = ref($class) || $class;
      What was wrong with it, and what was right and the whys of the scenarios. I now understand what people think, and have altered a sizeable chunk of code to use the appropraite structure. If that thread hadn't been there I would have continued on blithly thinking my code was clean, when in fact it was cluttered. All because I had read it in an O'Reilly Perl book and thought it was the Right Thing(TM). So what I am trying to get at here is, its great that you are questioning the norm in terms of what you are righting, be careful not to blithly(sp?) write off a particular notation because you want to be an individual

      On the actual thread at hand, I also do the same as the original poster,
      begin sub, validation, algorithm, return
      I also tend to attempt to make sure I only have one return, and to nest my code in such a way, as to get to a single return line, as opposed to returning from multiple points. I also always attempt to name what is going to be returned "return" with the appropriate sigil. Which again makes me more efficient as I can quickly scan a body of code, and determine exactly where my return value is being built, as opposed to having to guess, whats going to end up coming back

      If I am going to return an array for example I always populate @return, if I encounter errors, I clear the array, set 0 to some NULL val, and then elem 1 to an error string. Then the calling function need only test elem 0 for truth, or what have you, and respond appropriately.
      With this style I find it easier to write quasi concise routines (depends on what you are doing), with a fairly limited testing structure, which in turn leads to faster, easier to debug code. Which I like :)


      /* And the Creator, against his better judgement, wrote man.c */
        Purists are theorists, not do-orists. I'm a do-orist. Let's say I have a N-tree of objects and some function that walks the tree and executes itself on each child of a given node. Now, I want to stop walking the tree if any child returns 0 instead of 1.
        # Impure sub walk_and_do { my $self = shift; foreach my $child (@{$self->children}) { return 0 unless $child->walk_and_do; } return 0 unless $self->do_my_stuff; return 1; } ##### # Pure sub walk_and_do { my $self = shift; my $rc = 1; foreach my $child (@{$self->children}) { $rc = $child->walk_and_do; last unless $rc; } unless ($rc) { $rc = $self->do_my_stuff; } return $rc; }
        I think that the first is clearer and cleaner. There are less levels of indentation. Torvalds says in his style guide that there should never be more than 3 levels of indentation. If you're constantly checking codes and values, that simply won't work. I often find it harder to read code with 1 entry and 1 exit vs. 1 entry and N intelligently-designed exits.

        Exit when appropriate, not when some schmuck with a bunch of letters after their name tells you. I work for a living.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Focusing only on the #END foo markers, I find it interesting that you mention vi. Personally, I find using % to bounce between openning and closing braces much nicer than having to 1) clutter my code with countless #END foos, and 2) think about the foo to #END foo mapping when looking for the end of it.

        Of course, as you mention in another post, this is all personal style. Sometimes it's unfortunate that everybody thinks their own style is the best. :)

Re: A matter of style
by Aristotle (Chancellor) on Feb 15, 2003 at 02:24 UTC

    Goto:

    The apprentice uses it without thinking.
    The journeyman avoids it without thinking.
    The master uses it thoughtfully.
    This can be applied to basically all "purist" concepts equally.

    Makeshifts last the longest.

Re: A matter of style
by FoxtrotUniform (Prior) on Feb 14, 2003 at 19:48 UTC

      I'll never return from the "middle" of a routine as i find it makes debugging a little more difficult as there are multiple "areas" where the routine can be exited from. Beside the semantic validation at the top of the routine the exit will always be at the bottom before the }

      Purists say there should only be one entry and one exit and anything else is obfu. What do you say?

    For values of "purists" equal to "unreformed Pascal programmers". Sure, returning from all over your subroutine might be disorienting, but so will the contortions you're going to go through to return once from a routine that damn well should have multiple exit points. The same argument applies to other purist bugbears, like gotos and global variables. They can make your code harder, or easier, to read, depending on the problem and the circumstances. Ignoring them out of some bizarre sense of ideological purity is stupid.

    --
    F o x t r o t U n i f o r m
    Found a typo in this node? /msg me
    The hell with paco, vote for Erudil!

Re: A matter of style
by demerphq (Chancellor) on Feb 14, 2003 at 22:38 UTC

    Purists say there should only be one entry and one exit and anything else is obfu. What do you say?

    One entry to a subroutine yes. One exit no. Many people have disagreed with this point and for good reason. It increase code clutter, it increases code complexity, and often increases code duplication. About the only really useful argument that I can think of for only having one exit to a routine is to be able to positively determine the returned value. But theres lots of ways around that without losing clarity.

    sub one_exit { my $foo=shift; my $return=shift; CORE:{ last CORE unless $foo; #... last CORE if $foo eq "bar"; #... } return $return }

    or even easier is to just rename the sub for a bit and create a wrapper that calls it, allowing you to intercept its entry and exit, without artificial constraints confusing your code.

    ---
    demerphq


      When using procedural languages, I usually try to maintain a single exit from a procedure. I have had several occassions where I had to add some cleanup code at the end of a procedure. Since the procedure had multiple exits, I had to do some searching to find all of them and then rework the code so it would all fall off the end. On the other hand, I'm not a purist -- if the code starts getting too twisted in order to pull this off, I'll use additional returns or (gasp!) a goto.

      Lately, though, I've been working more with object oriented languages than with procedural languages where this has been less of a concern. Most of the things that would need cleaning up get handled automatically by destructors of objects going out of scope. In case of errors, I'm probably using a throw instead of a return, though.

      In perl, a common exit can easily be implemented with a naked block inside the routine. Use last instead of return inside the block and have all cleanup code following the block. I've seen similar things done in C with a do { ... } while 0;.

      --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
        If you have a procedurial language and you have multiple exit points from a procedure, and then you want to do some "exit" actions, you could do the same trick as you would with an OO language. You mask the procedure by another one, that calls your original procedure, and then does the exit actions. Except that with an OO language, you typically create a new class that calls a procedure with the same name in the original class, but with a procedural language, you rename the original procedure, and create a new procedure with the original name, that calls the original procedure, and then does the exit actions. Same technique, different syntactical details.

        Abigail

        In perl, a common exit can easily be implemented with a naked block inside the routine.

        I provided an example of this in my node. :-) I also mentioned the approach that Abigail-II suggests.

        ---
        demerphq


Re: A matter of style
by BrowserUk (Patriarch) on Feb 15, 2003 at 03:16 UTC

    I disregard purists and puratism, just as I do all forms of dogmatism, in code and in life. Whilst most dogma starts life as useful rules of thumb, once they become elevated to "Thou shalt not..." rules, they become constricting instead of enabling.

    The master carpenters adage, 'measure twice, cut once' is extremely good advice for any occasional DIYer, but if the same master carpenter was offered employment on the basis that he would always measure twice, he'd probably pass.

    With respect to the particular 'one entry-one exit' rule, Maybe you'll forgive me if I lapse into another analogy. Can you imagine if every road started at one city/town/village/district/house and ended at another? Or if you had to have a seperate waterpipe from source to every house?

    Branches are useful. Tee's are useful. I understand the sentiment behind it. Really I do. And in the past I have written some torturous code attempting to comply with it.

    I think that (for me) the most important word in that oft-denied acronym that isn't, is Practical. It's that one word and Mr.Wall's greater concept underlying it, that defines the way Perl is. It's that one single notion that made and continues to make perl so useful and usable. It's also what makes it fun.

    If there is one thing that I fear with the advent of the drive to Perl 6 it's that that element of the language may get watered down and lost somewhere along the way in favour of more 'correct' notions. I know I am not alone in this fear, though I don't have quite such a pessimistic view of the future as some.

    In sincerely hope that LW has the strength, energy and resolve to incorporate those features that will allow stricter adherance to some of the purer OO-concepts and provide for extension of existing syntactic sugar where these 'fit', without allowing the language to become bogged down with the 'Thou shalts' and 'Thou shalt nots' that constrain, complicate and frustrate in many other languages.

    Time will tell, but from what I seen of what's coming out of the Perl 6 camp, we're "safe in his hands".


    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Re: A matter of style
by chromatic (Archbishop) on Feb 14, 2003 at 17:18 UTC

    I do the same. It fits the way I test, for one -- starting at the top of a sub and checking every branch along the way. It also leads to shorter code. I put every brace on a new line, which eats up a lot of space. By avoiding if/else blocks wherever possible, I use less vertical space. (This isn't always possible, but there's a lot of potential for simplification.)

Re: A matter of style
by steves (Curate) on Feb 15, 2003 at 10:51 UTC

    Purist theory often doesn't match reality. I have a story that illustrates that.

    Way back when I was a C programmer we hired a well meaning QA head. One of her tasks was to bring in some code analysis tools. The engineering staff was tasked with evaluating them. We immediately set out on a realism test: Take a few pieces of heavily used common code that had few bugs in their source code revision tree and throw those at the tool. Then take some of our worst code -- mostly code we had outsourced -- that had pages and pages of revision history related to bug fixes and throw that at it. The bad code won. When we probed into why, a few things became obvious:
    • The code analyzer liked run-on initialization code in the bad source that set things to hard coded values. It liked that code because there were few branches (no conditionals).
    • It disliked the complexity of our common code. Most of that code was complex because we were hiding complex problems from the rest of the code. So there were a lot of branches, etc. to handle the complexity and present it to the rest of the code in a simpler manner. That code was factored much better than the bad code (smaller well defined functions, etc.) but the analyzer, when looking at it as a whole, seemed to disregard that.
    • It disliked some of the code constructs we found resulted in fewer bugs, such as not necessarily having only one exit point if that made the code hard to maintain.
    The QA head was not pleased, which we found even more amusing. She started to insinuate that we were wrong since the analyzer used "standard metrics" that "don't lie." Our argument was that history is even less of a liar. She quit not long afterward. Score one for engineering. 8-)

    This was over 10 years ago so I'm guessing a lot of those tools may be better now. But I think it's still true that a lot of theory doesn't match reality. The best guage of whether a given style is good is to look back historically at different coding practices and styles and see how they hold up in the real world.

Re: A matter of style
by Anonymous Monk on Feb 14, 2003 at 19:29 UTC

    I say your subroutines are way too big. I almost never validate parameters to subroutines. Instead I validate the input. After that any other validation is redundant. How do I debug my subroutines? I write them small and incrementally test them as I build (I did mention your subroutines are too big).

    As for the doublespeak of the “Code Purists,” this is stuff you regurgitated to get a good marks in college. “Subroutines should have only one entrance and only one exit” is part of their “goto”-less coding. They insist on using state variables, whose contents must be examined to determine what to do next, rather than making the routing explicit. But using state variables is obfuscation. When you are walking-through the code, you have to remember what state each is in and scan the code that isn’t active until you find some that is. With “goto” statements like return, last, next, redo, and die; you can skip the intervening code and get on with your walkthrough.

    I never put in “end of” comments; I use Vim which automatically matches parentheses as I type. It also automatically indents every time I type ‘{’ and outdents when I type ‘}’. I can easily find the beginning of every end.

Re: A matter of style
by l2kashe (Deacon) on Feb 14, 2003 at 18:41 UTC
    Note/Update: This was a response to dragonchilds reply, but I could not see the node. I apologize if this appears in the thread twice, but I didnt want it to get lost in the shuffle, so I moved it to a direct response
    # Your code # Pure sub walk_and_do { my $self = shift; my $rc = 1; foreach my $child (@{$self->children}) { $rc = $child->walk_and_do; last unless $rc; } unless ($rc) { $rc = $self->do_my_stuff; } return $rc; } # Same function, single return, just as clear (for me) # ala TIMTOWTDI sub walk_and_do { my($self,$flag,@return); $self = shift; for ( @{$self->childer} ) { (last && $flag = "$_->{err}") unless $_->walk_and_do; } if ($flag) { @return = ('0', "$flag"); } else { @return = $self->do_my_stuff || ('0', $self->{err}); } return(@return); }# END sub walk_and_do
    I don't want this to spiral downwards. What we are talking about here is PERSONAL style. For me its easier to maintain a single entry and single exit. Ill deviate when appropriate, but I tend to try and keep things straightforward. It makes it easier *for me* to maintain and extend my code.

    /* And the Creator, against his better judgement, wrote man.c */
      Also, if one doesn't like normal, "deterministic" multiple exit points, then one must be horrified by the concept of exceptions.

      But when multiple exit is used in the case of error conditions, exceptions make things even cleaner.
      sub walk_and_do { my $self = shift; $_->walk_and_do for @{$self->children}; $self->do_my_stuff; # could throw an exception. } eval { $root->walk_and_do; };
      The fact that do_my_stuff could throw an exception means that any of the recursive calls to walk_and_do could exit early, via the exception. And that is as it should be.

      jdporter
      The 6th Rule of Perl Club is -- There is no Rule #6.

Re: A matter of style
by jonadab (Parson) on Feb 15, 2003 at 17:27 UTC
    I'll never return from the "middle" of a routine as i find it makes debugging a little more difficult as there are multiple "areas" where the routine can be exited from. Beside the semantic validation at the top of the routine the exit will always be at the bottom before the } Purists say there should only be one entry and one exit and anything else is obfu. What do you say?

    I think it depends on the application and on the routine. There are cases where having multiple return points makes for clearer, more readable code than the alternatives available. I don't have a good example in Perl off the top of my head, but here's one in another language... the following is a parse_name routine I wrote for a class of objects (matches, as it happens). (The language is Inform, and is mostly self-explanatory if you are familiar with computer languages in general. You do need to know that the switch statement implicitely breaks after each case, unlike C.)

    What makes multiple exit points really necessary is that we're parsing a stream of words, and at any point when one does not match, we have to stop; yet, the same word may match or not match depending on a variety of conditions that depend on the state of the object. Here is the code...

    I cannot imagine the obfuscation that would result from trying to make that routine (or a longer one like it) exit in only one place. A couple of additional variables would be needed, plus additional conditionals, and the for loop would become needlessly complex, and it would just be a big mess -- especially for a longer routine. (I chose a relatively short parse_name routine for simplicity of example; they can be much longer if, for example, certain words only match if certain other words are also used, in certain sequences, and so on and so forth. If you have an eighty-line parse_name routine, you do NOT want it exiting in just one place.)

    Now, it can certainly be argued that this parsing problem is atypical; it is certainly atypical of the kinds of things we usually use Perl for. So there may well be lots and lots of cases where a single exit point is desirable. All I'm saying is, there are also cases where that's not so.

    sub A{while($_[0]){$d=hex chop$_[0];foreach(1..4){$_[1].=($d %2)?1:0;$d>>=1;}}return$_[1];}sub J{$_=shift;while($_){$c=0; while(s/^0//){$c++;}s/^1//;$_[1].=(' ','|','_',"\n",'\\','/' )[$c]}@_}$PH="16f6da116f6db14b4b0906c4f324";print J(A($PH));

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2024-04-26 00:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found