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

Progressing my programming and have a few simple questions to ask. this is one. if I have a sub that does some function
sub doSomething { my ($var) = @_; print $var; }

Say I have a case where If $var equals a particular value I want it to print in a different way. What's the best way to add this extra functionality cleanly.

To add some perspective I have a large legacy code base that has some nice subs for creating html output but they are littered with little if functions so that the sub does something slightly different if x or y is true.

I can see 2 options

Any thoughts?

Replies are listed 'Best First'.
Re: Best way to handle small changes to subroutines
by almut (Canon) on May 26, 2010 at 06:38 UTC
    I could copy the sub into a new sub that implements basically the same functionality but with this small change.

    Don't.  In the long run, and in the large scale, this will create a maintenance nightmare. For example, if you later realize that there's a bug in one of the copy-n-pasted common code fragments, or when you need to make some modification, you'll have to apply the fix/change in every place that same code appears...  Not only is this tedious, but experience has shown it is often not done properly, introducing new hard to track bugs.

    See also the (more generally scoped) anti pattern Cut-And-Paste Programming.

Re: Best way to handle small changes to subroutines
by Anonymous Monk on May 26, 2010 at 06:22 UTC
    I would create two more subs altering the content and have them invoke the printer sub -- atleast that's what I do for logging when in need of collapsing structures before logging.
    sub doSomethingX { my $string = shift; $string =~ tr/foo/X/; return doSomething($string); } sub doSomethingY { my $string = shift; $string =~ tr/foo/Y/; return doSomething($string); } sub doSomething { my ($var) = shift; print $var; }
Re: Best way to handle small changes to subroutines
by LanX (Saint) on May 26, 2010 at 16:05 UTC
    > Any thoughts?

    It's a far to general question to be answered easily, could you show us some code?

    > # I leave the if statements but then when you call a sub you can't really tell what it will return. As it can vary depending on what if's it might match.

    I would suggest to write a wrapper¹ to this legacy code, controlling the state of these global flags

    sub wrap_render { local $x=shift; local $y=shift; if ($var) { return "your change"; } else return render(); } }

    like this you have full control about this "alien" function.

    As a general principle I prefer code to be easily understandable and avoid to clutter it with if statements which eventually turns the flow into a labyrinth. Furthermore I try to localize global vars as tight as possible.

    So instead of something like

    sub render_a { print "<a "; print "style='$css'" if $global_css_flag; print ">" }

    I would write something like

    sub render_a { my $style=get_css(); print "<a $style>"; } { my $css_flag; sub get_css { return "style='$css'" if $css_flag; } sub css_flag { if (@_) {$css_flag=shift} else {$css_flag} } # gette +r-setter }

    (untested)

    Cheers Rolf

    UPDATE: added checking of new flag $var.

    ¹) in perl you can give the wrapper the same function name like the wrapped function you're calling from within! Just ask if you wanna go this way!

Re: Best way to handle small changes to subroutines
by ikegami (Patriarch) on May 26, 2010 at 15:03 UTC

    Sometimes the simplest code is still hairy.

    You might be able to benefit from callbacks, e.g. changing

    sub render { my ($self, $obj) = @_; ... ... if (...) { ... } else { ... } ... ... }
    to something like
    sub render { my ($self, $obj) = @_; ... ... $obj->render_foo(...) ... ... }