Generalisation. Refactoring. Reuse. Craig Larman suggests to "pick your battles", but I often have difficulties, also because Perl gives me tools to make powerful things in a few keystrokes, so I ask myself: "Why not"? So I begin...

Suppose you need a simple filter function, e.g. to detaint variables that you've already checked to be good. I've come up with something similar:

sub detaint_1 { $[0] =~ /^(.*)$/; return $1; }
Writing such filter functions, I often wonder whether I should provide an in-place modification version; for this particular example, it would be useful to have deparsing happening in-place, because the variable is actually trustable (assumed that due checks have been done), so I come up with the following:
sub detaint_1_inp { $[0] =~ /^(.*)$/; $[0] = $1; }
This has the added advantage to avoid variable copy, which could be expensive if they're big chunks of texts. In-place modification gives the user the ability to choose: if she wants a copy, just copy and call the function on the copy; otherwise, just apply the function to the original variable.

But what if I'll need to detaint more variables at once, for example after having performed cross-checks on them (think of two variables, one holding a directory name and another a file name in the directory)? I can easily extend the approaches:

sub detaint_n { map { /^(.*)$/; $1 } @_; } sub detaint_n_inp { foreach (@_) { /^(.*)$/; $_ = $1} }
Obviously, these results could be obtained with the one-argument version as well (I swear that I read the reply from BrowserUK to my snipped here):
my @a; # ... set @a ... my @b = map { detaint_1 } @a; # Copy detaint_1_inp($_) foreach (@a); # In-place
but I wonder: wouldn't it be useful to provide all these behaviours at once with a unique interface? So, I finally came up with the following monster, taking advantage of the three different context I can call a function, i.e. list/array, scalar and void:
sub detaint { my $subref = sub { $_[0] =~ /^(.*)$/; $1 }; return map { &$subref($_) } @_ if (wantarray); # Copy for arrays return &$subref($_[0]) if (defined(wantarray)); # Copy for scalar $_ = &$subref($_) foreach (@_); # In-place return; }
which can be easily refactored to get a general filter applier for more functions:
sub apply_filter { my $subref = shift; return map { &$subref($_) } @_ if (wantarray); # Copy for arrays return &$subref($_[0]) if (defined(wantarray)); # Copy for scalar $_ = &$subref($_) foreach (@_); # In-place return; } sub detaint { return apply_filter(sub { $_[0] =~ /^(.*)$/; $1 }, @_); } # Refactored code leads to reuse! sub left_pad { my $padding = shift; my $minlength = length($minlength); return apply_filter(sub { my $v = shift; if (length($v) < $minlength) { ($padding . $v) =~ /(.{$minlength})$/; $v = $1; } $v; }, @_); }
Back to Planet Earth, my question is: do I really need all this? I'm quite a novice when it comes to this kind of forecasts, and I read that newbies often tend to over-generalise, solving problems that they could have but that they will actually never have. Is this kind of generalisation an example of this?

Flavio (perl -e "print(scalar(reverse('ti.xittelop@oivalf')))")

Don't fool yourself.

In reply to Writing general code: real world example - and doubts! by polettix

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.