Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

RFC: Perl Second-Best Practices

by dimar (Curate)
on Dec 18, 2005 at 18:08 UTC ( [id://517610]=perlmeditation: print w/replies, xml ) Need Help??

Recently in the Chatterbox, while musing about perl idioms and whatnot, a well-known perl advocate interjected that he was considering writing a book on "Perl Second-Best Practices."

This interjection was of course recognized as a humorous remark, but it got me to thinking. Why not? There *must* be times when you think to yourself:

"Hmmm ... I know this shouldn't be in my code, but ..."
and then you apply whatever justification to go ahead and do it anyway.

Sometimes those justifications are out of ignorance. Sometimes they are not. The kind I am interested in are the latter.

Specifically: are there any "Second-Best" practices that you use on a regular basis? If so, why? I post this to see if any of you are willing to publically admit to it. You know you're out there.

=oQDlNWYsBHI5JXZ2VGIulGIlJXYgQkUPxEIlhGdgY2bgMXZ5VGIlhGV

Replies are listed 'Best First'.
Re: RFC: Perl Second-Best Practices
by markjugg (Curate) on Dec 18, 2005 at 20:24 UTC
    I will hardcode a magic number in the code and mark it with an comment next to it like "# XXX should be in config file".

    I do it because I want to stay in the flow of programming and feel it will be easy to return later for the brain dead task of moving the number out to a config file instead.

    If I knew the number would need to appear multiple times throughout a code base, I'd probably go ahead and add it to a config file immediately.

    As part of my refinement process, I'll grep the code for XXX comments to see if anything has been flagged for later attention.

      Ohh, that brings back (bad) memories.

      In $CPAN/src/unsupported/4.036/perl-4.036.tar.gz, you'll find a file named lib/chat2.pl, which contains:

      unless (socket(S, 2, 1, 6)) { # XXX hardwired $AF_SOCKET, $SOCK_STREAM, 'tcp' # but who the heck would change these anyway? (:-)
      Yes, these were the correct constants on BSD, but they were wrong for SysV, which meant that every SysV user sent me bug reports about why chat2 didn't work for them. {sigh}

      Thankfully, that file was "retired" as of Perl5, being replaced by the Expect module.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        Finally easily accessible as... http://chat2.pl! Yes, I bought the domain just for the joke!

        -- Randal L. Schwartz, Perl hacker

        The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

      Yeah, I do that. I use TODO instead of XXX as the comment flag, but it amounts to the same thing. I've also been known on many occasions, despite whatever shred of sanity I may possess, to hardcode filepaths (although, I usually at least put them in a lexical variable at the top of the file). The thing is, I know better. I know that most of my Perl code eventually ends up running on at least both *nix and Win32, but I continually leave myself this cleanup to do the first time I have to run any given program on the other system.

      At least I've finally just about got myself trained to use File::Spec::Functions::catfile instead of hardcoding the directory separator.

Re: RFC: Perl Second-Best Practices
by radiantmatrix (Parson) on Dec 19, 2005 at 15:31 UTC

    The "second-best" thing I do regularly is to use path strings instead of building them with the File::Spec functions. It's all ActiveState's fault: their version of Perl for Win32 lets me get away with using open my $FH, '<', './data/source.txt' or die($!), where as other Win32 versions of Perl will not DWIM on the forward slashes.

    This has bitten me more than once when one of the scripts I write for work gets run on a box using PXPerl...

    <-radiant.matrix->
    A collection of thoughts and links from the minds of geeks
    The Code that can be seen is not the true Code
    "In any sufficiently large group of people, most are idiots" - Kaa's Law
      Maybe you shouldn't use either one, since we have Path::Class?
Re: RFC: Perl Second-Best Practices
by qq (Hermit) on Dec 19, 2005 at 21:44 UTC

    In certain circumstances I like very short variable names. For example in a loop where the variable is used many times as the topic, and I want the eye to be drawn to the methods. To me:

    for my $e ( @episodes ) { $e->method_one; $e->method_two; $e->method_three; }

    is clearer than:

    for my $episode ( @episodes ) { $episode->method_one; $episode->method_two; $episode->method_three; }

    However my coworkers don't seem to like it, so I'm going to try and change.

    update: s/@episode/@episodes/ in second example.

      I tend to do the same thing myself, but only in places where it isn't likely to cause confusion. For instance, if your loop had lots of other one-letter variables or if there were several that all started with "e", noticing the $e might be difficult.

      That’s not a second-best practice at all, particularly if the loop variable just iterates over a well-named array or a (really) self-explanatory expression. F.ex., I’d rewrite foreach my $index ( 0 .. $#somearray ) { wibble( $index, wubble( $somearray[ $index ] ) ); } to use $i instead.

      Length is not a goal for naming variables; choosing them so the code is easier to read is. That means a name needs to be long and descriptive if the variable’s scope is large, but conversely also that it should be shorter for a more tightly scoped variable. Picking one-letter identifiers for loop variables on short loops helps readability. (Of course, if the list expression is actually very complex, you will probably want to use a longer name to describe what the expression means. Naming things is a complex craft.)

      Makeshifts last the longest.

Re: RFC: Perl Second-Best Practices
by dave0 (Friar) on Dec 20, 2005 at 04:28 UTC
    Oh, wow, where to start? There are a lot of nasty things I do in Perl that are actually necessary. Sometimes, they're necessary simply because the code is (originally) intended to be a quick one-off for debugging or proof-of-concept purposes, so spending 3 hours doing it "right" loses out to spending 10 minutes to get it done. And sometimes, they're necessary because there simply isn't a nicer way of doing it.

    Here's a sample "second-best" pattern that I've used recently, that causes co-workers and bosses to cringe, despite being reasonably sane and acceptable. I've seen it pop up all over, most recently in merlyn's SysAdmin article:

    ... { no strict 'refs'; *{"${class}::get_${name}"} = sub { ... }; } ...
    The "no strict 'refs'" and symbol-table mucking is certainly justified, because there's really no better way to do it, but it still feels "second-best" to me.

      sfink is right. Also, japhy noticed recently that disabling strict references at the top of the scope there disables them inside the anonymous subroutine. It's better to declare the subroutine and then disable strict references and assign to the typeglob:

      { my $sub = sub { ... }; no strict 'refs'; *{ "${class}::get_${name}" } = $sub; }
        *{; do { no strict 'refs'; \*{ "${class}::get_${name}" } } } = sub { . +.. };

        Makeshifts last the longest.

      I'm not very good at symbol table stuff, but it seems like you could spell that out with less punctuation and in a strict-safe way with
      $main::{$class."::"}{"get_$name"} = sub { ... }

        Not if $class contains "::" (at least not on the last version of Perl I tried it on).

        [ Though, I suppose you could throw Data::Diver into the mix to solve that problem and get a much more complicated solution that meets some irrational fear of ever disabling 'strict' :) ]

        - tye        

Re: RFC: Perl Second-Best Practices
by vrk (Chaplain) on Mar 30, 2017 at 09:13 UTC

    A few years ago at work, I had to optimise the running time of a CGI script that is part of a bigger reporting system. The program architecture is a bit strange; in this case, the problem was accessing inherited package variables (yes, this is a thing). The class hierarchy is only three levels deep, but the variables in the leaf class get millions of accesses in a script run and many of them come from the parent or grandparent class. The variables were accessed using inherited methods.

    Instead of redesigning the architecture (which is still on the todo list), I wrote a subroutine that takes a list of variable names as input (like '%FOO', '$BAR'), traverses @ISA breadth first and inspects the symbol table of each package it encounters. If it finds a typeglob with the right name and a slot of the right type, the sub imports that slot into the calling package. Of course, the subroutine checks the symbol table of the calling package for %FOO and $BAR before the expensive lookup.

    I guess it's more about working around a suboptimal software architecture, but you couldn't solve it like this in certain other programming languages.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (7)
As of 2024-04-19 10:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found