Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Code style question

by AlexP (Scribe)
on May 20, 2021 at 15:26 UTC ( #11132778=perlquestion: print w/replies, xml ) Need Help??

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

Hi monks!

I'm new to perl and already like this language. To learn it, I decided to write a module. However, there is not enough information on the code style.

There is an official https://perldoc.perl.org/perlstyle which is a bit superficial with a few examples. I also came across the following two sources: https://github.com/chusqui/perl-style-guide and https://github.com/htrgouvea/perl-style-guide, who partly contradict each other and even with official perlstyle. Finally i found https://metacpan.org/pod/Perl::Tidy and applied it to my code... Something really strange happened.

So could you please show me the way or good resources about code style?

Also here is my module source code https://github.com/AlexP007/perl-data-dot/blob/main/lib/Data/Dot.pm.

I'll be very thankful if you could tell me what can be done better and what's the best way to format code.

P.S. So what's the right indent: 2 or 4?

Replies are listed 'Best First'.
Re: Code style question
by eyepopslikeamosquito (Bishop) on May 21, 2021 at 02:07 UTC

    A quick scan of your module and I'm very impressed! Fantastic start for a Perl beginner! Just a couple of minor points I noticed after a quick scan of your code:

    sub data_get(+$;$) {

    Unless things have changed recently with the introduction of new Perl signatures, the traditional Perl code style advice has always been an emphatic "Don't use prototypes" -- see, for example, item 122 "Don't use subroutine prototypes" at Perl Best Practices. Googling just now turned up this this article by brian d foy on the newer experimental subroutine signatures (which I have no experience with).

    This line of code from your module:

    our $VERSION = '1.0.0';

    is definitely wrong. It should read:

    our $VERSION = '1.00';
    This is one item that PBP unfortunately got wrong as mentioned here. See also Writing Solid CPAN Modules for general advice on writing CPAN modules.

    Update: As noted by haukex here: our $VERSION = "1.23"; seems to be the most compatible with the various Perl tools that parse code to find information on modules.

    I maintain a long list of general references on code standards and style advice at: Re: I need perl coding standards (Coding Standards Links)

      You are great community and Perl is my best now! Thanks for tips and tricks and your time.

      It takes several weeks for me to examine all this information and in the end i refactored my module and create style guide here. Maybe it will be helpful for other neofits.

      PS. There is a big style node by eyepopslikeamosquito on PerlMonks. Could be useful if you are interested in this topic.

      WoW! You rocks, really helpful.

      It looks like my weekend promises to be interesting with lot's refactoring and studying perl.

      I'am neofit to perl, but have little experience in go and php.

Re: Code style question
by Fletch (Chancellor) on May 20, 2021 at 15:36 UTC

    I usually use this config for perltidy that mirrors (mostly) the recommendations from Perl Best Practices (and it uses 4 spaces).

    ## PBP perltidy RC file -l=78 # Max line width is 78 cols -i=4 # Indent level is 4 cols -ci=4 # Continuation indent is 4 cols -st # Output to STDOUT -se # Errors to STDERR -ce # cucddled elsen (XXX my pref) -vt=2 # Maximal vertical tightness -cti=0 # No extra indentation for closing brackets -pt=1 # Medium parenthesis tightness -bt=1 # Medium brace tightness -sbt=1 # Medium square bracket tightness -bbt=1 # Medium block brace tightness -nsfs # No space before semicolons -nolq # Don't outdent long quoted strings -wbb="% + - * / x != == >= <= =~ !~ < > | & >= < = **= += *= &= <<= && += -= /= |= >>= ||= .= %= ^= x=" # Break before all operators

    At first glance nothing about your sample file there looks particularly egregious (although your usage of prototypes is maybe a bit suspect; in most cases unless you're trying to affect how perl parses things in a weird way you don't want to use them (that being said the new signatures are a slightly different story)).

    Edit: Also after another closer read looking at what the code's doing rather than formatting it looks like you may be reimplementing an existing wheel (see e.g. Data::Diver).

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      Thanks for your config, it's quite helpful.

      As for prototypes, I've often heard that they are almost never needed and your remark just proved this. So, I'll get rid of them.

      Data::Diver is cool, but i need practice in perl =) Maybe you know resource with module ideas?

        Nothing wrong with reimplementing wheels for pedagogical practice so long as you're aware that's what you're doing.

        As far as module ideas, some of the questions here can provide interesting things to poke at (e.g. Challenge: Generate a glob patterns from a word list recently). Or if you're of a mathematical bent maybe something like Project Euler problems. Working through some more general CS problems in SICP or code katas might be another thing to try.

        The cake is a lie.
        The cake is a lie.
        The cake is a lie.

Re: Code style question
by ikegami (Pope) on May 20, 2021 at 15:55 UTC

    So what's the right indent: 2 or 4?

    A principle you often see mentioned in a Perl context is TIMTOWTDI (pronounced "tim toady"), short for There Is More Than One Way To Do It. I think some take it too far on occasion, using it to justify alternates which are objectively meritless, while I believe it means 1) one should be tolerant of differences and maybe even learn from them, and 2) adjust to what's best based on context.

    With that in mind, anything that might be claiming to be an official style guide is merely making suggestions. So while your answer is inherently unanswerable, I'll leave you with the following:

    From what I've seen, 4-space indents is by far the most common indent used, so I recommend that you use this. You will also come across 4-position tabs and 2-space indents pretty often. I use something I haven't see anyone else use (for somewhat historical reasons), so I won't mention it.

    There is one "rule": Be respectful of the conventions of projects to which you collaborate.

    Seeking work! You can reach me at ikegami@adaelis.com

      Indenting style is just that, indenting style. There is no official answer to this indentation question. I have a preference for 3. That doesn't mean that 2 or 4 is "wrong".

        Yes it is wrong. Wait . . . I'm sorry, was this just the five minute argument or the full half hour? :)

        Edit: 98% an unserious comment solely to make the Python (Monty) reference.

        The cake is a lie.
        The cake is a lie.
        The cake is a lie.

      Thanks for your reply.

      TIMTOWTDI is one of the things that attracts me, but for perl neofit it could be quite complex to start without accurate information.

      Hope this node will be useful not only for me.

Re: Code style question -- code review
by Discipulus (Abbot) on May 20, 2021 at 19:17 UTC
    Hello AlexP and welcome to the monastery and to the wonderful world of Perl!

    Style is anyway a matter of taste. For what my opinion is worth I glanced your code and I'd say:

    @EXPORT and @EXPORT_OK are different: the latter makes no sense if you already export some function.

    Do you really need Exporter 5.74 and Scalar::Util 1.56 ? You must be as flexible as you can with users of your module: no need to ask them to upgrade to last version unless you know is the rigth thing to do. For example let say Scalar::Util included the blessed function from x.x version but you know your usage of it can trigger a bug up to x.y verion then and only then you ask the end user to have x.y version.

    Many authors use names with a leading underscore for private functions, even if they are not private.

    I prefere the and put at the end of the line and all and aligned: the same for or and for thernary like ? and : because somenting at the end of line is easier to spot.

    In your sub get_by_single_key you have if .. if .. if and this, style apart, sounds wrong: if .. elsif .. else sounds more appropriate.

    You set all return explicit and this is good and make the code more readable. Someone likes shorter statements like returns 1 if $x but this is a matter of taste.

    I dont like too much blank lines (again a matter of taste): for me, closing a brace } does not need a blank line after it.

    L*

    PS you might be interested in my step-by-step-tutorial-on-perl-module-creation-with-tests-and-git even if i see you already implemented some test: good job!

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      "I prefere the and put at the end of the line and all and aligned: the same for or and for thernary like ? and : because somenting at the end of line is easier to spot."

      I emphatically disagree! The easiest stuff to see is at the start of the line. I frequently break complicated expressions over lines so that it is easier to understand them. For example, the following test from a C++ project I'm working on right now could be laid out several ways:

      if (currMaj < bestMajVer || (currMaj == bestMajVer && currMin <= bestM +inVer)) // Current image is no better than the best so far if (currMaj < bestMajVer || (currMaj == bestMajVer && currMin <= bestMinVer) ) // Current image is no better than the best so far if ( currMaj < bestMajVer || (currMaj == bestMajVer && currMin <= bestMinVer) ) // Current image is no better than the best so far

      To my eye the last version is much easier to understand than the previous two.

      One of Perl's features that I really like is the provision of statement modifiers because, for short statements at least, I can get compact expressive code with the important bits in the right order:
      <do this interesting thing> <while/for/if> <something vaguely interesting>.

      For the same reason the default increment operator should be pre-increment (++$thing) instead of the cargo culted post-increment operator ($thing--). There are places where post-increment must be used, but they are rare and the default should always be pre-increment just because the operator is easier to see and the operation is less surprising.

      Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
        Hello GrandFather

        > I emphatically disagree!

        :) as I told, I suppose is a matter of taste. I tend to use something like:

        # complex clause if ( defined $thing and $thing > 3 and $thing <= 42 and 0 == $thing % 2 ) # ternary print (defined $thing and $thing > 0) ? $thing : 'not';

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Thank you very much for your time and detailed comment.

      According to your information, I can make a small manual.

      About versioning, is there a way to tell perl use version >= 1.x or what can be done?

        For using modules, the version specified is, by default, the minumum version. The same is true of perl itself, so:

        use 5.010; use Text::Diff 1.40;

        means that the script must be run using perl 5.10 or newer and must be able to load Text::Diff version 1.40 or newer.

        See the docs for use for more detail.


        🦛

Re: Code style question
by tangent (Vicar) on May 20, 2021 at 15:57 UTC
    Get yourself a copy of the book 'Perl Best Practices'. There is also a module called Perl::Critic which you can run your code through and it will highlight where you are deviating from the guidelines in the book. It can be a bit annoying at first but it is highly configurable and well worth it in the long run. Here is a short introduction.
      Perhaps the most important advice in Damion's book appears early in Chapter 2.
      All that matters is that you adopt a single, coherent style; one that works for your entire programming team. And having agreed upon that style, that you then apply it consistently across all your development.
      Bill

        Note about teams sounds very reasonable.

      Take suggestions with a grain of salt. But yeah, it could definitely be a rewarding experience.

      Seeking work! You can reach me at ikegami@adaelis.com

      Perl::Critic seems very interesting.

      And thanks for the book. It's not the first time I've heard about 'Perl Best Practices', so going to find my copy.

        Welcome AlexP to The Monastery

        I too am a fan of Perl Critic. Since being introduced to it here in The Monastery a few months ago, I have tested all new code against it. I especially like that different levels of scrutiny can be set. I like to get code to pass the 'stern' test but always look beyond that so I can learn...and ignore the stricter elements that don't suit my use case.

Re: Code style question
by GrandFather (Saint) on May 21, 2021 at 00:05 UTC

    As a general thing there is no "Right" code style, although there are plenty of wrong styles. Mostly, if you have thought about your style at all and are consistent the results will be pretty good. Looking at your module code it seems likely you have thought about style and are consistent and the results are pretty good.

    With that in mind, there is no "Right" indent size. Like several others I mostly settle on 3 spaces (always spaces - never tabs) to indent all my code, except Perl! Because I contribute a reasonable amount of code to PerlMonks my Perl style tends to conform more to Perl norms which include 4 space indents and K&R layout. Like I said, there are no rights and consistency is King (at least within a language).

    I also frequently use Perl::Tidy to clean things up after a heavy refactoring session (for example). It is a great tool and can be configured to generate pretty much whatever your preferred coding style is. It can take a while to beat its configuration into the right shape, depending on how far your style is from Perl::Tidy's defaults. But it's worth the effort of doing so that you can be comfortable to bash out some code then quickly tidy it up with Perl::Tidy.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

      Thanks for you time and comments.

      This is not the first time I've heard about 3 spaces. There is something to think about.

Re: Code style question (updated)
by LanX (Sage) on May 20, 2021 at 15:50 UTC

      Thanks for the helpful links, going to explore them today.

Re: Code style question
by tobyink (Canon) on May 21, 2021 at 16:49 UTC

    Having looked at your code, it looks pretty well-formatted to me. Code style is very much a matter of personal preference.

    That said, don't indent all your lines in pod. In pod, whitespace is significant, and lines which are indented are treated as code blocks.

      Got it, will use whitespaces in pod more semantically.

Re: Code style question
by Marshall (Canon) on May 20, 2021 at 15:43 UTC
    I haven't looked seriously at your code. But this question: P.S. So what's the right indent: 2 or 4? is clear. The answer from multiple papers is 3. That gives a slight advantage over 2. 4 causes problems with lines becoming too long without increasing readability over 3. I am sure that my statement will be controversial. If 2 or 4 are the only options, then use 2.

      "Then shalt thou indent to three, no more, no less. Three shall be the number thou shalt indent, and the number of the indenting shall be three. Four shalt thou not indent, neither indent thou two, excepting that thou then proceed to three. Five is right out!"

        This will be a great start for the book!

      Really? I thought I was the only using that! Back in the Turbo Pascal days, indents levels were all over the place, and I settled on 3 for exactly the reasons you mentioned. Been using it ever since.

      Seeking work! You can reach me at ikegami@adaelis.com

        Wow, Turbo Pascal! That brings back memories...

        I hired a guy to write a test program for me. Running 24 hours per day, it took about 5 days to reach a result.
        I knew that the problem lay in a buffer compare routine.
        I had the guy rework the code such that this was a sub which "touched" all the vars that I needed.
        I took the floppy back to my office and hacked in the binary code for the new "string" operations that Intel had for the 80186. Cut the execution time down to about 8 hours.

        PS: I still have a pre-production 6 Mhz IBM PC with a 5MB Quantum hard card. Free to anybody who wants it. Production models were 8 Mhz. This thing boots and works, even has Lotus 123 on it!

        This 3 has very solid evidence in CS studies. And for the reasons that we both agree upon.

      Indents are four spaces ;-) ... but I note that Cpanel::JSON::XS uses three spaces by default in pretty-printing JSON. (I override it, lol...)


      The way forward always starts with a minimal test.

      Also (2+4)/2 is 3. Looks nice.

Re: Code style question
by Anonymous Monk on May 20, 2021 at 18:07 UTC
    The code looks quite clean. Yes, a run through "perltidy" might be an experiment. I like the way that you used blank lines to separate unrelated blocks of code.

      Nice to hear this!

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (6)
As of 2021-12-06 18:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    R or B?



    Results (33 votes). Check out past polls.

    Notices?