Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

where do you put your subs

by greenFox (Vicar)
on Mar 08, 2002 at 06:19 UTC ( [id://150240]=perlquestion: print w/replies, xml ) Need Help??

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

I have a habit of putting all my subs at the bottom of the file. I have always figured that any-one looking at the code only needs look at the code for a sub if they need to, the function of the sub should be apparent from its name. And when I am coding I write a bit at a time in a modular fashion and I don't want to have to go tripping over all those subs to get the programs main loop.

I have noticed though that some coders have their subs at the top of the file. perlman:perlstyle is quiet on the subject. I am wondering if there is any reason to prefer one style over the other

--
my $chainsaw = 'Perl';

Replies are listed 'Best First'.
Re: where do you put your subs
by demerphq (Chancellor) on Mar 08, 2002 at 10:10 UTC
    Actually I strongly strongly disagree with the "put the subs at the bottom" school of thought. (In fact its closely related to the subject that was behind the very first post I ever made at the monastery) I suppose originally this comes from programing systems languages like Pascal and C where you _cannot_ use a function prior to its declaration (contrary to webadepts assertions this has nothing to do with "making you think things through" it has to do with simplifying compiler design, both of these languages can and usually are parsed in a single pass.) In either of these languages you need to place a forward declaration in situations where you have two subs that need to refer to each other.

    But when you think it through it makes a lot of sense. You declare variables before they are used so that you (and the compiler) know about them. In fact this is also one of the primary reasons why I still do this in Perl even though I dont need to (I can forget forward decls tho, yah!).

    Even in perl legal syntax is different depending on the order of declaration. When a sub is used before it is declared it MUST be referenced with parenthesis ( bar() )or the & (&bar) sigil. It cannot be used in bareword form ( bar ). This alone is enough of a reason to always declare what you use before you use it.

    use strict; sub foo{print "Foo\n"} foo; bar; #produces error! sub bar{print "Bar\n"} __END__ Bareword "bar" not allowed while "strict subs" in use at D:\temp\order +.pl line 4. Execution of D:\temp\order.pl aborted due to compilation errors.
    And Im sorry to say to those who defend the "subs last" idea, but there are even more serious arguments why putting subs first is a very very good idea. Consider when you write your "main" do you wrap it and all of its variable declarations in a block? If you don't then when you put them at the top of the file _all_ of your subs are now treating your file scoped lexicals as globals. And globals are something to be avoided if at all possible as every good CS student knows. So now this means that you may _think_ that you have written your subs as nice reusable pieces, but in fact they may have subtle dependencies on the "main" that you placed before them, and you wont even know. This is obviously a very bad thing.

    Now this is going to sound harsh, in fact there are some that will probably -- me for saying it, but without hearing a very very good justification or seeing a bunch of fiddly stuff (anonymous blocks, BEGIN statements and the like) to resolve the issues above I would usually mark down or consider a programmer to be an amateur/newbie if I see "subs at the end". And if I had to work on the code, the absolute first thing that I would do is reorder the code (and most times when I do it breaks because of the "unintended global" issue) with some very strong comments if the original programmer was near.

    Given all of the disadvantages related to "subs last" and the very very few advantages asscoiated I can't see why anyone would do this.

    PS:There is even less reason to place use statements at the top of a file than there is to place subs at the top of the file, but its pretty damn confusing figuring out where a subroutine call gets defined if the use statements are scattered all over the place.

    PPS:I find it interesting that of the other responders to your post at this point I only agree with one Juerd++ (well, I dont mind mixing code and pod...)

    Yves / DeMerphq
    --
    When to use Prototypes?
    Advanced Sorting - GRT - Guttman Rosler Transform

      The lexical/unintented-global problem needs a little more visualization. In the chatterbox, some are really confused about this part.

      # Not using strict, for demonstration. sub at_top { print "Foo is: $foo\n"; } # This is the body of the script, where a head-to-tail flow is in effe +ct my $foo = "I wanted this to be visible only for the body, not all of m +y subs!"; at_top(); # "Foo is: " at_bottom(); # "Foo is: I wanted ..." sub at_bottom { # We're in the same lexical scope!! print "Foo is: $foo\n"; }


      Using strict, but not getting a warning? Yep, because $foo is an "unintended global" (thank you for giving the phenomenon a name, demerphq)
      use strict; my $foo = "blah"; my $bar = "hello, world!"; sub mistake { print $foo; # Works, and prints blah }

      ++ vs lbh qrpbqrq guvf hfvat n ge va Crey :)
      Nabgure bar vs lbh qvq fb jvgubhg ernqvat n znahny svefg.
      -- vs lbh hfrq OFQ pnrfne ;)
          - Whreq
      

      demerphq

      Normally I agree with your post but on this one I have to disagree. ++ for a well articulated post, I just don't agree with it. I think your argument hinges on one tiny aspect of perl - using a sub name to invoke it without any syntactic sugar. I like the sugar! I think most perl devs spend too much time playing golf - that sugar helps me. I like the visual clues. When I see bar its hard for me to know what the heck that is but when I see bar() (my pref) or &bar, I instantly know what that is.

      Now for my reasoning on why subs should be after (an implicit or explicit main) - it's easier to read. I love to read - newspapers, magazines, web sites, books, code, books on code. There is a definite well designed, well thought out, and well documented approach to writing - it's called the funnel method where the first paragraph is your general outline (moving from general to hypothesis with each sentence). Succeeding paragraphs are the specifics that support your hypothesis. I strongly believe code should follow this method because coding is just another form of writing and communicating. Think about it.

      Now for you personally, the subs first is great but for someone coming behind you, you're asking them to disavow every other type of writing and succumb to your approach. Much like reading a James Joyce novel, a lot of people will praise you but only a select few will read you the whole way through and even less will emulate you. Hemingway is a better approach - simple, straightforward and very little verbosity. I only ask you to think about those poor slob maintenance programmers who have to come behind you. It's much easier to start at the top and see the general outline of the writing then to skip to the last chapter.

      Being able to read the code is of much greater value than how fast it runs, how few resources it uses, and definetly less than how the compiler or interpreter goes about it's business. Needless to say we definetly cannot reduce down to "See Dick Run" but we can definetly employ a straightforward, almost shaker, style as oppossed to a baroque one.

      -derby

      update: Also, I would never think one was an amatuer for putting sups at the bottom but I would think I was dealing with a pascal convert if I saw them up front (and I would re-arrange it).

        The parens/ampersand are not much of a real problem. The unintended globals are! If you declare a lexical in the body of your script, and you have the subs declared after that, those subs can access the lexical, thus having global-like behaviour (in a way). A very, very good programming concept is to keep things to yourself if you're a piece of code.

        Normal writing does not have the details at the beginning, that's true. But they don't have the conclusion and flow at the beginning! The introduction in writing can be compared to loading modules, using strict. Then, explanation comes, so you can understand the rest of the text. When that's done, body and conclusion follow.

        Subs, in my opinion, are not footnotes, they form information _required_ to understand the rest of the code. That's another good reason for putting small subs that just encode data, and don't have to do much with program flow in separate modules (footnotes...).

        A Perl program is executed in order. Unless you want it otherwise, it will end after having evaluated the last statement, which should be logically the end of the file. And it's a reason to put your subs at the top too! For the same reason you put use statements at the beginning: they are required pieces of knowledge to be able to fully comprehend the rest of the code.

        44696420796F7520732F2F2F65206F
        7220756E7061636B3F202F6D736720
        6D6521203A29202D2D204A75657264
        

        where the first paragraph is your general outline (moving from general to hypothesis with each sentence). Succeeding paragraphs are the specifics that support your hypothesis. I strongly believe code should follow this method because coding is just another form of writing and communicating. Think about it.

        Your analogy doesnt makes sense. The main is in essence the conclusion of an argument. So what you are saying is that when I write an argument I should put the conclusion before the introduction.

        Also, you are talking about aesthetic reasons. I am talking about best practice. Best practice is that which minimizes the chance of bugs and error, not that which reads like a novel. If you want to read nice text then read the comments. The code should be written so as to be as maintainable and error free as possible.

        And if you rearranged my code as you said there is a very good chance it wouldnt run. I do like not using parens when they arent necessary as they often end up occluding the intent in a mess of parens, much as lisp is practically unreadable for most mere mortals. Consider

        print join("\n",map(join(",",map{s/\.//;$_}@$_),@strings); #vs print join "\n",map{join",",map{s/\.//;$_}@$_}@strings;
        Err. maybe not the best example but I know which of the two I find easier to write and to read.

        UPDATE:
        A better example is one that we use all the time, that of finding out how many values are in a hash. Which would you rather use

        my $count=scalar keys %hash; #or $count=scalar(keys(%hash));
        END UPDATE

        BTW: I am a Pascal programmer by background. But that is neither here nor there. In C you cant use a sub until it has been declared either,(Both allow the use of forward declarations, as does perl,) in fact most true compiled languages share this trait.

        Cheers,

        Yves / DeMerphq
        --
        When to use Prototypes?
        Advanced Sorting - GRT - Guttman Rosler Transform

        Now for my reasoning on why subs should be after (an implicit or explicit main) - it's easier to read. I love to read - newspapers, magazines, web sites, books, code, books on code. There is a definite well designed, well thought out, and well documented approach to writing - it's called the funnel method where the first paragraph is your general outline (moving from general to hypothesis with each sentence). Succeeding paragraphs are the specifics that support your hypothesis. I strongly believe code should follow this method because coding is just another form of writing and communicating. Think about it.

        I guess that depends whether you're a "top down" or a "bottoms up" programmer.

      Subs at the top? Subs at the bottom? What's next? Should we discuss whether toilet paper should roll from the top or bottom? :-D Seriously, DeMerphq gives some excellent reasons why you might put your subs at the top, but I've also seen lots of good reasons why you'd want your subs at the bottom. The "unintended global" problem is often a feature, not a bug: yes, I do use global variables (judiciously, and deliberately, and with full knowledge of what I'm doing) and when I do I declare them... at the top of my program. This makes perfect sense to me, as the order of events is:
      use statements my $foo; # LOOK I'M A PACKAGE GLOBAL WOO HOO! main loop/program logic subs
      The subs are all black boxes (mostly, except where they use the package globals), which means (in my mind) it shouldn't make the slightest bit of difference where they appear in code order. They aren't executed "in order" so order becomes immaterial.

      But you know, that's what makes sense to me. Some people are completely allergic to () so they declare their subs first. I don't mind typing "foo()" so I don't care. If you don't like globals (and want to go whatever means necesary to keep from using them, either on purpose or accidentally) hey, more power to ya. I think they're kinda spiffy, and my code is brutally consistent as to how and when I declare them and use them.

      All in all I think perlstyle is silent on this because it really is a matter of taste, and TMTOWTDI.

      Perhaps next we'll discuss proper tab indentation. :-D

      Gary Blackburn
      Trained Killer

        but I've also seen lots of good reasons why you'd want your subs at the bottom.

        Really? But you dont list any.

        The "unintended global" problem is often a feature, not a bug: yes, I do use global variables (judiciously, and deliberately, and with full knowledge of what I'm doing) and when I do I declare them... at the top of my program.

        Then how can you call them "unintended globals"? The point I was making is that a programmer might think that by making lexical declarations in file scoped main that those lexicals are private to the main code. But they _arent_. Whereas what you are talking about is a proper global variable declaration which belongs (if they must be used) as you say at the top. BTW the code snippet you posted has a misnomer

        use statements my $foo; # LOOK I'M A PACKAGE GLOBAL WOO HOO! (wrong) # NO ITS NOT ITS A FILE SCOPED LEXICAL # PRETENDING TO BE A PACKAGE GLOBAL main loop/program logic subs
        The subs are all black boxes (mostly, except where they use the package globals), which means (in my mind) it shouldn't make the slightest bit of difference where they appear in code order. They aren't executed "in order" so order becomes immaterial.

        On face value I agree with you. Properly written it shouldn't matter. But the issue here is best practice. And best practice should be oriented towards whatever minimizes the chance of error, especially anoying hard to trace errors like the 'unintended globals' that I mentioned before. I have no issue if someone wants and specifically uses globals. But shouldnt have to guess that they are globals and that they are intentional. It is for these types of reasons that various rules of thumb (consult tillys homenode and nodes for various lists of them, and a link to good books on this subject) have developed. These rules are not set in stone but are followed by the vast majority of professional programmers because they do minimze the possibility of error in the long run. (Examples would be that code should be indented (heh you mentioned that facetiously and here I am addressing it seriously) between 2 and 8 spaces, with the optimal being 4 spaces, trying to ensure that subroutines are no more than 1 page long, putting short parts of a conditional before the long part.)

        I think that perlstyle avoid this becuase the level of programmer it was intended for is expected to know of these conventions and issues to make an educated decison (as you have, all the credit to you) as to how they wish to procede. Howeve this site has monks of every level of expertise and accordingly it is a responsibility (IMO) of those of us with the expertise to proscribe best practice and not our personal preference. When the newbies know enough to argue they probably wont argue becuase they'll know th reasons why we are saying what we are saying to the newbies...

        Cheers,

        Yves / DeMerphq
        --
        When to use Prototypes?
        Advanced Sorting - GRT - Guttman Rosler Transform

      > When a sub is used before it is declared it MUST be
      > referenced with parenthesis ( bar() )or the & (&bar)
      > sigil. It cannot be used in bareword form ( bar ). This
      > alone is enough of a reason to always declare what you
      > use before you use it.

      This alone is reason enough not to. God forbid we clearly seperate methods from scalars. (Sorry. I just never understood the attraction to this Perl quirk.)

      ()-()                                                      ()-()
       \"/    DON'T   BLAME   ME,   I  VOTED   FOR    PACO!       \"/
        `                                                          ` 
      

      First, let me say that I gave this node a ++ despite the fact that I'm about to disagree with most of it, and take offense at some part of it. But you make your arguments in a clear, readable fashion :-).

      That having been said, I consistently put subroutines after their first use. Except in a few cases where the cross-referencing was so thorough that I resorted to alphabetical ordering1 for lack of a better scheme. Even then, the subroutines come after the main logic. In a later node, you tweaked someone for saying that there were good reasons, but that he hadn't offered any. Here are some of mine.

      The flow of thought tends from the least-specific to the most specific. I am first interested in knowing that the program opens a file, operates on the content, and then outputs a report. From that point, I will (depending on what I'm trying to learn-- am I debugging this? Am I adding new features?) choose to delve more deeply into what type of processing, exactly, is being done. Now, that's probably in a subroutine somewhere. And from where I'm at in the source code, it's not important whether the sub is above me or below me. But I really don't want to scroll through several pages of subroutines to finally find the main logical loop, and then find that I only need to look at one subroutine which, by the way, I passed about 3 pages ago. I don't generally know what subroutine I care about when I first start reviewing code. After that, when I know a specific name, the placement is irrelevant-- I'm going to /-search in vi or Ctrl-S in XEmacs, depending on what's available to me.

      Forget not that there is a use subs (); just as there is a use vars (); pragma. I try to pre-declare all my subroutines, because I generally plan before I start banging out code anyway. I want to know within the first 15-20 lines of code what all the subroutines and package-global variables are in a program or module. I should be able to get that much information with a simple head invocation. Again, where the subs themselves are doesn't even matter here. If you don't use the subs pragma and do all your declaration management by ordering, I'm going to have to read all of your code to find out what is there. Think you would gripe at me if you had to read my code with the subs at the end? If you're one of my assigned engineers and you bring me code for review that has to be read all the way through just to know what subroutines are defined and declared, we'll be having a conversation.

      Want more? How about this: The end of the file in a Perl script is not the same as the end of the program. What about modules that use AutoLoader2, or scripts that use SelfLoader3? Scripts often embed data (other than subroutines) after __END__ or __DATA__. In those cases, putting subroutines "at the end" isn't even technically possible. Worse, if the actual logical loop of the program is sandwiched somewhere between subroutine blocks and whatever follows __END__, how much more intuitive is that to the reader?.

      What something like this ultimately comes down to, is in fact an evaluation of how well-designed your code is (or was) before typing began. Consistency in style is more important than adherence to a specific style. As programmers, we will always be exposed to styles different than our own. Whether or not we can read them and derive the information we seek from the code, that is what we need to judge the programmer against.

      And lastly, show some caution when making heavily-generalizing statements like, 'I would usually mark down or consider a programmer to be an amateur/newbie if I see "subs at the end"'. I do take offence at it, and I imagine there are other Perl coders who would, as well. Constructs like:

      exit main(@ARGV);

      only serve to make Perl code look more C-like. But C is not a scripting language, and everything in C, including main, is explicitly a subroutine. You don't have a situation in which a C program will start at the first execution instruction, thus requiring you to wrest control avay from the errant Program Counter and direct it to where you want it. Instead, a linked C program includes code that starts execution at the linker-provide entry point for main()4.

      I've been programming Perl as a full-time job for almost 10 years, well before 5.000. When I write C, it looks like C. When I write Tcl or Lisp, that's what the code looks like. And my Perl looks like Perl, surprisingly enough.

      --rjray

      1 Yes, I have done this once or twice, only when there was no other clear and obvious way to order them. If the order is going to be arbitrary anyway, then it at least helps to know that read_file will come somewhere before report_error.

      2 What I Want, When I Want It: Using AutoLoader and AutoSplit. Originally in The Perl Journal Issue #6.

      3 Ibid.

      4 In truth, a lot of stuff generally happens before the actual entry into the main routine, none of which is really relevant to the argument at hand.

Re: where do you put your subs
by webadept (Pilgrim) on Mar 08, 2002 at 06:47 UTC
    I use to place all my functions first out of habit, as my first training in programming was from Pascal. In Pascal you can't call a function or a procedure if it is listed below the function or procedure you are calling from. (that use to be the case anyway, haven't used that language for several years now, and Delphi doesn't require this sturcture)

    It was explained to me (way back then) that the reason for this encumberance was that the programer had to give structure to his/her thoughts before writing code. I have to admit that because of this my "thought" on code is probably better than if I was taught first with a more "open" means of programming, such as Perl and C allows. You couldn't just say "hey, I need a function" and just throw it in there. It kept code clean and tight.. in my opinion anyway. I'm sure that others would have a more practical view point on this, such as "damn, I need a function here"

    I have since changed to putting the main program above and functions below, for exactly the reasons you describe, its easier to go through the code, and most of my stuff is Object programming these days, so its more or less a mute point.

    Update

    I have since learned of the possiblity of unexpected Global variables, and I belive Globals are the seeds of the DEVIL :-) Out of habit I declare all variables with my so this keeps the possiblity of Global variables sneaking into the effects of my scripts, but thought I would mention this, incase you don't read further down to some of the great posts below this one.

    Glenn H.
    webadept.net
Re: where do you put your subs
by abaxaba (Hermit) on Mar 08, 2002 at 06:38 UTC
    This is simply a matter of taste, IMHO. But, I have no "main" code, per se. rather..
    #!perl use strict; use Modules; main(); sub main { #main algorithm, calls to other subs } sub1 {#sub code} sub2 {#sub code} etc..

    I find this method to be extremely helpful in having variables with a limited scope. Just say "NO" to globals.
      I like to do
      #!/usr/bin/perl -w exit main(); sub main { ... return (0); }
      Maybe I'm just a C programmer at heart.



      1. dude, what does mine say?
      2. "sweet", what about mine?
      3. "dude", what does mine say?
      4. GOTO 2
        The code-flow is not really logical: why do you exit before performing your tasks? Is there any reason to have the exit statement before the sub declaration?

        And real C programmers at heart write some for (;;) instead of ... 4 GOTO 2 :)

        44696420796F7520732F2F2F65206F
        7220756E7061636B3F202F6D736720
        6D6521203A29202D2D204A75657264
        

Re: where do you put your subs
by George_Sherston (Vicar) on Mar 08, 2002 at 13:05 UTC
    My practice is, if I'm writing a script called foo.pl, to write a module called foo.pm. Then all I have in foo.pl is the flow control, which is either a dispatch table or an if / else tree, made up of calls to subroutines in foo.pm. The subs in foo.pm are arranged "by order of appearance" in foo.pl.

    I don't claim this is either original or perfect, but it works for me for the following reasons:
    • makes my subs immediately available for re-use elsewhere - which is a good thing in itself, but also subliminally gets me thinking about code re-use
    • enforces loose coupling - each sub has to be passed and to return all its inputs and outputs - so I am forced to think about minimising inputs and maximising usefulness of outputs
    • I'm a bit unusual in that I do all my development on a remote server. Given that, I find it useful to write each new sub in a module which I call dev.pm, which has nothing in it except (a) the sub I'm working on now and (b) some useful de-bugging shortcuts (eg print out the contents of a data structure using Data::Dumper). Then when the sub is ok, I cut and paste it into foo.pm (or whatever). So the module with the subs in it grows and grows, but I rarely look at it, whilst the files I'm working with stay slim. Saves seconds that I can use for staring blankly into space
    • foo.pl acts as an "index" of my subs

      § George Sherston
Re: where do you put your subs
by BeernuT (Pilgrim) on Mar 08, 2002 at 06:27 UTC
    I prefer this type of setup:
    #!/usr/bin/perl use (pragmas); use Modules; my $var; declare any global variables here main code goes here Then my subs are at the bottem. usually in order of importance
    It's just the style that I adapted to. I have no paticular reason to use it other than its what keeps me sane :) I have tried to put subs at the top, in the middle, spread around, but I like having all my code in the order above. Makes it easier for me to work with.

    -bn
Re: where do you put your subs
by djantzen (Priest) on Mar 08, 2002 at 07:18 UTC

    I like to group subs by category, and alphabetically within the category. So, I often do:

    package Hello; # constructor new {} # accessors getA {} getZ {} # mutators setA {} setZ {} # instance methods doA {} doZ {} # class methods doA {} doZ {}
    If there's a main method this typically goes at the end.

Re: where do you put your subs
by dragonchild (Archbishop) on Mar 08, 2002 at 14:29 UTC
    Personally, I like the 40,000 foot view of things, and I like seeing the 40,000 foot view of things when I'm working on someone else's code. So, I like to see the main logic first. Subroutines, to me, are abbreviations, or replacements. They say "I'm not really an operation, but a link to a series of operations." They're shortcuts, abbreviations, macros, etc. (I'm going to get killed for that statement.)

    So, I've got my actual logic flow right there, for everyone to see. It's got a bunch of these 'links' to groups of operations. If I want to see a subroutine definition being used in the top level, I don't want to go far. So, all the top-level subroutines are first, in order of invocation. Then, the next level, etc. At some point, I just start chucking things into modules.

    That's just my thought. I understand demerphq's view on things, wanting to remove unintended side-effects. But, in my mind, that's reverting to the shotgun we all want to use. If he feels he needs the shotgun, that's fine. I personally feel that I know what each and every one of my variables do, and where its scope is, so I don't need the shotgun.

    I so rarely declare file-scoped lexicals that, when I do, it's for the express purpose of creating a file-scoped global. *gasps from the audience* Globals, just like "goto LABEL", have their purpose. But, that's another node.

    ------
    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.

      I agree with this sentiment. IME most of the time I do not need to understand every nuance of how a script works -- implementation details. (Not that they're not important, but most of the time I don't care since, depending on the author, someone has already thought about the problem longer than I have.)

      So why should I have to plow through all the subroutines to get to the interesting part, the logic that binds them all together? And properly named subroutines should eliminate the need to read a routine just to find out what it does -- for instance, I'd probably have to see what a routine sortev does but not sort_by_estate_value.

      Chris
      M-x auto-bs-mode

Re: where do you put your subs
by Juerd (Abbot) on Mar 08, 2002 at 08:26 UTC
    My subs are always at the top. In my opinion, a sub should be in the file before the point where it's first used. If that isn't possible, for example when two subs call eachother, I put empty declarations above them. If you have subs before everything else, you don't have to wrap it in a BEGIN block if you need simple closures.

    My sripts look like this:
    #!/usr/bin/perl -w use Module::Foo; use Module::Bar; use Module::Baz qw(foo bar); use strict; sub first { # ... } sub second { # ... } # main code, if applicable


    My modules look like:
    package Module::Xyzzy use Module::Foo; use Module::Bar; use Module::Baz qw(foo bar); use base 'Exporter'; use Carp use strict; our @EXPORT_OK = qw(...); sub CONSTANT () { 1 } sub new { # I try to always put new before other methods } sub first { # ... } sub second { # ... } sub DESTROY { # If there's a DESTROY method, I put it at the end } # main code - that is: "1;" :) __END__ =pod That's right, I use __END__ and =cut, just to be sure. My documentatio +n is NOT mixed with the code. Whenever code is unclear, I comment it, but I dislike, +no I hate pod and code mixed. =cut


    It's just a matter of taste

    ++ vs lbh qrpbqrq guvf hfvat n ge va Crey :)
    Nabgure bar vs lbh qvq fb jvgubhg ernqvat n znahny svefg.
    -- vs lbh hfrq OFQ pnrfne ;)
        - Whreq
    

Re: where do you put your subs
by seattlejohn (Deacon) on Mar 08, 2002 at 06:50 UTC
    Where do I put my subs? In modules, of course ;-)

    Seriously, though, if I'm going to keep things in a single file I almost always put the subs toward the bottom. That way I get the main logic first, so when I open the file I can more easily get a 40,000-foot view of things. If I want to drill down, I can page down in my edit or search for "sub xxx". Not as easy to search for the beginning of the main code, IMO.

    I used to do things the other way, probably because I first programmed in languages where you had to define subs before you could refer to them. Once I discovered Perl let me put subs at the end, I switched over and have never looked back... but admittedly, it's a personal preference / coding convention as much as anything.

(tye)Re: where do you put your subs
by tye (Sage) on Mar 08, 2002 at 15:59 UTC

    This first part is partially in response to demerphq's node elsewhere in this thread where he mentions my use of exit main;. But I didn't want the rest of this to get lost too deep in this large thread.

    I mentioned this habit here, and I actually make an exception for main() and call it before I declare it. I define main() at the very bottom of the script for the same reasons many people put their "main" code near the top... You see, you can't put your "main" code at the very top, you have to put your #! line, your modules uses, your file-scoped variables (that act like "globals"), your package variables (real "globals"), etc. before everything. In a real-life script, that introductory cruft can get rather long and usually isn't the most interesting part of the program.

    So by putting main() at the very bottom of the script, it is easier to find than if I put it as close to the top as I can get away with.

    But I call main() via exit( main(@ARGV) ); as close to the top as possible for reasons currently partially covered on tye's scratchpad.

    I also try to declare subroutines before I call them. Although the benefits of this are somewhat minor with current versions of Perl when using good practices, there are still some benefits (some mistakes that get caught for you). You can even intentionally avoid using parens with your function calls and get told at compile-time when you've mispelled a function name.

    But I suspect that the benefits will increase greatly with future versions of Perl. Having the ability to catch simple mistakes in how you called a function, especially at compile time, can be a great benefit. Not having to always declare how the function to be called is also a benefit that Perl will probably never lose. But I expect future versions of Perl to have much more support for this type of declaration and checking of function invocations (at compile time).

    And when you have that in a language, defining the function before you call it is nice. Now, sometimes you'll want to avoid having to perform a topological sort on your order of subroutine definitions so you'll put separate subroutine declarations at the top and define your subroutines willy nilly (or in some other sensible order) below. But sometimes that is a pain in itself and the topological sorting is easier.

    So I start out with my subroutines sorted topologically so that they are all defined before they are called except for main() which I call before any subroutines are defined (where "before" means earlier in the source code, not earlier in time, of course).

    I currently find practical benefits in this practice. But I suspect I'll be even happier with it when Perl 6 comes out, especially when I start converting old scripts to make use of Perl 6 features. (:

            - tye (but my friends call me "Tye")
Re: where do you put your subs
by mugwumpjism (Hermit) on Mar 08, 2002 at 16:53 UTC

    I think that a program should be composed of small pieces that are tested, flexible and pretty much atomic. Build the pieces up, prove to your own mind that they work 100%, and then assemble at the end.

    Hence, I normally put all "main" code at the end of the file. Superficially, so do most people whenever they "use" something; because the subs are being declared first.

    Every function should be able to stand on its own - all of its input parameters must be in @_. It's entire return should be via "return" (or updating objects passed). Therefore, the less variables unintentionally in scope, the better. Which is why we have packages and "use strict".

    As a matter of course, I put a large text marker near mthe start of program logic, and explicitly call exit():

    #====================================================== # MAIN SECTION STARTS HERE #====================================================== my ($main_vars, $so_on); main_code; exit(1);

    If a meme (sub in this case) is required to understand another piece of code, then that meme should come before the piece of code. Sometimes I put little "silly" functions at the end of the code - stuff that is more distracting than needs to be explained.

    This is called "bottom up" programming. The alternative, "top down", tends to end up with people thinking "hmm, what's the minimum I need to write to get this function to work?" IMAO*.

    see unify-dirs for an example. Note that the focus is less on where the subs end up in the file, but instead concentrates on the ordering of the memes - both in the source and the man page.

    * - In My Arrogant Opinion

Re: where do you put your subs
by greenFox (Vicar) on Mar 12, 2002 at 06:32 UTC

    Thanks and ++ to every-one who took the time to reply. I have picked up a couple of things to consider (especially "unintended globals") and I think I will be coming back to this node for a while as I refine my style.

    Cheers, Murray

    --
    my $chainsaw = 'Perl';

      And thats the rub. Despite my strong feelings I would agree that there are many points of view and many decent arguments both ways. The point is that knowing the issues (on both sides) comprehensively is the only way to come to a proper informed decision. And there are far more issues here than I think many would have thought on first look.

      Yves / DeMerphq
      --
      When to use Prototypes?
      Advanced Sorting - GRT - Guttman Rosler Transform

Log In?
Username:
Password:

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

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

    No recent polls found