Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

What's your programming style?

by harangzsolt33 (Chaplain)
on Dec 08, 2018 at 04:13 UTC ( [id://1226940]=perlquestion: print w/replies, xml ) Need Help??

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

Which programming style do you like? Which one should I use? (Now, disregard the fact that this sub may not actually work properly. :P But I just want to talk about the style here.)

Here are five examples:

# Style 1: "The Beginner" ########################################## # Returns the pathname separator character # which depends on the type of OS. # # Usage: STRING = GetPathnameSeparator() # sub GetPathnameSeparator { my $S = uc($^O); return ':' if (index($S, 'MACOS') >= 0); return '\\' if (index($S, 'WIN') >= 0); return '/'; # LINUX OR OTHER } # Style 2: "Neat" ########################################## # Returns the pathname separator character # which depends on the type of OS. # # Usage: STRING = GetPathnameSeparator() # sub GetPathnameSeparator { my $S = uc( $^O ); if (index($S, 'MACOS') >= 0) { return ':'; } if (index($S, 'WIN') >= 0) { return '\\'; } return '/'; # LINUX OR OTHER } # Style 3: "The one-liner" $SEPARATOR = index(uc($^O),'MAC')>=0?':':index(uc($^O),'WIN')>=0?'\\': +'/'; # Style 3: "somewhat condensed" # Returns the pathname separator character which depends on the type o +f OS. sub GetPathnameSeparator { my$Y=uc($^O); index($Y,'MAC')<0||return':'; index($Y,'WIN')<0||return'\\'; return'/'; # DEFAULT=LINUX } # Style 4: "black-hole density" sub GetPathnameSeparator{my$Y=uc($^O);return index($Y,'MAC')>=0?':':in +dex($Y,'WIN')>=0?'\\':'/';} # Style 5: "somewhat misleading/obfuscated" sub iii{$a=uc($^O);return(index($a,'MAC')>=0?':':index($a,'WIN')>=0?'\ +\':'/');}

Replies are listed 'Best First'.
Re: What's your programming style?
by eyepopslikeamosquito (Archbishop) on Dec 08, 2018 at 08:40 UTC

    Which programming style do you like? Which one should I use?
    Athanasius has already provided a much nicer alternative.

    I'll briefly nitpick your style of using the || operator (as in index($Y,'WIN')<0||return'\\';). For flow of control, prefer the low precedence or operator. A common example of preferring or to || is:

    open(my $fh, '<', $file) or die "error opening '$file': $!";
    That is probably the principal use case as to why the low precedence operators were added to the language in the first place. Reserve && and || for logical expressions, not flow of control, for example:
    if ($x > 5 && $y < 10) ...

    This is discussed in detail in Perl Best Practices, Chapter 4, "Values and Expressions" in the "Don't mix high- and low-precedence booleans" item.

    Re OS path portability, the core Perl module that deals with this is File::Spec and that is perhaps what you should be using (hard to know without understanding your bigger picture). Note that if you only need to target *nix and Windows (update: and modern Macs running BSD-derived MacOS), you can avoid File::Spec simply by using / as the path separator; this works because a little known fact is the Windows API treats forward slashes and back slashes equivalently at the C level in all file path arguments to all Windows API functions. A minor annoyance is that Windows commands typically use forward slash for command line argument options. So, while using forward slashes in file paths is fine when calling all Perl internal functions on Windows, using them in command line arguments when running Windows commands is problematic - in the rare cases where you need to pass a file path to an external Windows command, you can translate it like so: $filepath =~ tr{/}{\\}

    More useful than nitpicking low level details of programming style is to look at the bigger picture; some references on that follow:

Re: What's your programming style?
by Athanasius (Archbishop) on Dec 08, 2018 at 04:32 UTC

    Hello harangzsolt33,

    Since the value of $^O can’t change at runtime, SEPARATOR should be evaluated at compile time. Also, why use index and uc and a comparison, when a simple regex will do?

    use strict; use warnings; use constant SEPARATOR => $^O =~ /MACOS/i ? ':' : $^O =~ /WIN/i ? '\\' : '/'; print 'SEPARATOR is "' . SEPARATOR . "\"\n";

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Wow, you are a perl wizard! :-0
        That's not from an "Anonymous monk." I don't know how I got logged out. :P
Re: What's your programming style?
by davido (Cardinal) on Dec 08, 2018 at 12:51 UTC

    It's been years since I wrote Perl targeting Windows systems, but I seem to recall that there is no need, when dealing with paths from within Perl code, to differentiate between Windows and Linux flavor path separators. Indeed perlport has this to say:

    DOS, OS/2, VMS, VOS, and Windows can work similarly to Unix with / as path separator, or in their own idiosyncratic ways (such as having several root directories and various "unrooted" device files such NIL: and LPT:).

    When in doubt it's best to use a module known for its ability to bridge these sorts of gaps. Modules like Path::Tiny, File::Basename, File::Spec (or File::Spec::Functions), and so on. Used with a little care they can take the need for most OS-specific code in your primary codebases, and where they fall short, you should probably modularize your own solutions so that primary business logic is not peppered with OS-specific cruft.

    As for programming style, verbosity is not one of the virtues of a programmer. ....although you wouldn't know that by reading one of my wordy posts. ;)


    Dave

Re: What's your programming style?
by choroba (Cardinal) on Dec 08, 2018 at 13:59 UTC
    My style is very different to each of the proposals:
    my %SEPARATOR_BY_OS = ( darwin => ':', MSWin32 => '\\' ); sub get_pathname_separator { $SEPARATOR_BY_OS{$^O} // '/' }

    See Platforms in perlport for the possible values of $^O. Note that MACOS isn't part of any value and that your solution would return \ on Mac OS X, as

    index 'DARWIN', 'WIN' == 3

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      The document you refer to doesn't seem nor claim to be exhaustive.

      I don't have a Mac computer to check that, but it seems from other documents that $^O is equal to the "MacOS" string on a Mac computer (or, at least, it used to be so).

        The naming conventions are, at least in my opinion, easily confused. The use of spaces and capitalisation can make a lot of difference.

        For versions where $^O returns MacOS, see perlmacos (that's the most recent online perldoc [for 5.26.1]). Note the versions of Perl where support was dropped and then removed. See perlport (5.8.9) > PLATFORMS > Mac OS for historical information (including use of the ":" separator).

        Mac versions 10.x started roughly 20 years ago. They were originally called "Mac OS X". Around version 10.10 — I don't have exact information to hand — that became "macOS". (I don't know why.) They all use the "/" separator (same as any UNIX-like system).

        I have personal knowledge of versions from 10.7 "Mac OS X" to 10.12 "macOS" (I've used most but not all). To the best of my knowledge, for all of these versions, $^O has always returned darwin.

        $ perl -le 'print $^O' darwin

        Unless support for very old hardware is intended, coding for $^O returning MacOS is probably unnecessary (except, perhaps, for a warning about an unsupported operating system).

        — Ken

        Like others have said. It’s been 18 years since Mac started the move from 9 to X (a play on 10, uniX, and neXtstep). 17 years ago X was on all boxes with some dual/system boot options and a couple years after, 9 was gone. I was a dyed in wool Mac fan from the 80s (when all the good typesetting and music software was there) but by 1999 I was within a year of giving up on Mac for some kind of *nix when they made the leap, put out the beta, and I was allowed to remain in their camp.

        Salut, Laurent. Not for a long time has it been like that in my experience. I am on MacOS Sierra, but it's been darwin for as long as I can remember.

        $ perl -E 'say $^O' darwin $ perl -v This is perl 5, version 26, subversion 1 (v5.26.1) built for darwin-2l +evel $ uname -a Darwin MYHOSTNAME 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 21 20:0 +7:39 PDT 2018; root:xnu-3789.73.14~1/RELEASE_X86_64 x86_64

        See Re: Get macOS Version for recent discussion.


        The way forward always starts with a minimal test.
Re: What's your programming style?
by Laurent_R (Canon) on Dec 08, 2018 at 11:26 UTC
    Some brief remarks, taking into account that you're asking for comments on programming style.

    I'll refrain from suggesting a module, because that's clearly not what you're asking here, but that might actually be the best answer.

    Removing all spaces as in styles 3 to 5 is certainly not a good practice in terms of code readability.

    Although the use of index rather than a regex may in some cases be faster, this certainly does not matter in a subroutine that is (presumably and hopefully) called only once in your program. I would recommend using regexes in such a case, as this make the code somewhat simpler.

    A Perl beginner would most likely use style 2 ("Neat") rather than style 1 ("Beginner").

    Using single-character variables such as $S or $Y for storing the uppercase version of the OS is not the best choice for readability. Using $a is an even poorer choice. A variable name such as $os would already improve significantly legibility.

    In style 1, you don't need parentheses for the postfix conditional. Removing them would tend to reduce line noise.

    As you mentioned yourself, the subroutine may not work properly (as an example, you'll end up with a Windows separator if you're using Cygwin), but, with this limitation in mind, this is a suggested variation on style 1:

    sub get_path_separator { for ($^O) { # stores the OS in $_ to simplify the regex syntax return ':' if /mac/i; return '/' if /cyg/i; return '\\' if /win/i; return '.' if /vms/i; return '/'; } }
    My other favorite would be style 3, but spread over several lines to make the intent clearer:
    $_ = $^O; my $separator = /mac/i ? ':' : /cyg/i ? '/' : /win/i ? '\\' : '/';
    Please also note that launching Perl from a bash terminal under Windows, you might get something like "msys" as the value for $^O (I don't know why).
Re: What's your programming style?
by BillKSmith (Monsignor) on Dec 08, 2018 at 13:58 UTC
    The book 'Perl Best Practices' (ISBN 0596001738) suggests still another style for choosing a single value:
    use strict; use warnings; use English; sub GetPathnameSeparator { $_ = $OSNAME; my $seperator = # OS # Seperator /MACOS/i ? ':' : /WIN/i ? '\\' : '/' ; return $seperator; }
    Bill
Re: What's your programming style?
by ikegami (Patriarch) on Dec 08, 2018 at 06:09 UTC

    Is this used for parsing or generating paths?

    If it's used for parsing paths, then the fundamental assumption that a system only has one path separator is flawed. (Windows accepts both \ and /.)

    If it's for generating paths, providing the separator is a very poor interface. See Path::Class for a better interface.

Re: What's your programming style?
by dsheroh (Monsignor) on Dec 08, 2018 at 09:58 UTC
    None of the above.

    1) Too many comments. Good names remove the need for most/all of them.

    2) What's with all this CamelCase naming? Normal Perl practice is underscore_joined_names.

    3) Why are you doing this yourself instead of using one of the many fine CPAN modules that handle it?

    4) If you must roll your own, a regex match is much Perlier than index and, therefore, more likely to be instantly understood by someone looking at the code. I question whether the average Perl beginner would even understand your "The Beginner" version unless they're already familiar with index from past experience with other languages. (Also, the use of postfix conditionals (return if rather than  if () { return }) is rather idiosyncratic to Perl and often treated as either "advanced" or "to be avoided", rather than a "beginner" technique. I disagree with that view, but it seems to be relatively common nonetheless.)

Re: What's your programming style?
by Anonymous Monk on Dec 08, 2018 at 08:59 UTC
    They all use comments instead of documentation :)

    Path::Tiny

Re: What's your programming style?
by tobyink (Canon) on Dec 10, 2018 at 15:20 UTC
Re: What's your programming style?
by Anonymous Monk on Dec 11, 2018 at 04:50 UTC
    #!/usr/bin/perl use strict; use warnings; use Config '%Config'; sub GetPathnameSeparator { =head2 GetPathnameSeparator Return the character used to separate elements in the command shell search PATH. =cut return $Config{path_sep} }
      return $Config{path_sep}

      I don't think that's the "separator" the OP's code is looking for.
      $Config{path_sep} returns the symbol that separates the pathnames in $ENV{PATH}, but I believe the OP's code is looking for the symbol that separates the individual directories within a pathname.

      Cheers,
      Rob
        I don't think that's the "separator" the OP's code is looking for.

        OP is looking for style, not functionality. Document your subs!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-25 05:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found