Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Indent, anonymous sub, or lexical sub for module private code?

by 1s44c (Scribe)
on Jul 31, 2014 at 07:26 UTC ( [id://1095687]=perlquestion: print w/replies, xml ) Need Help??

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

Monks,

I have a subroutine in a module that takes a data structure and runs the exact same page of code on two inputs from that structure. What's the recommended way to reuse that code?

The code already has a bunch of loops and ifs so I'm hesitant to just wrap it in a another loop as it will disappear off the right of my screen. I don't really want a global sub that will only get called exactly twice. I think I want a lexical sub but they are experimental and others might want to run my code on perl <5.18. Is an anonymous sub the right thing here? Copy and paste just seems wrong.

What's the best way to reuse my chunk of code?

EDIT: Changed the title to something more descriptive.

  • Comment on Indent, anonymous sub, or lexical sub for module private code?

Replies are listed 'Best First'.
Re: Code reuse question
by salva (Canon) on Jul 31, 2014 at 08:50 UTC
    There is no problem in having a subroutine that is just called from two places, or even just from one.

    Those are usually called helper subs or methods and are very common and useful to structure your code in a better way, improving its readability. Don't be afraid to use them as much as you want!

    Lexical subs have the advantage that they do not pollute the namespace, but hey, that's a minor issue. Don't let the presence of the new feature force you to stop doing things the old way. Really, that's a very minor issue, that doesn't create problems in practice.

Re: Code reuse question
by zentara (Archbishop) on Jul 31, 2014 at 09:01 UTC

      I don't get the Perl Weekly newsletter. Why don't I get the Perl Weekly newsletter? I'll sign up at once!

Re: Code reuse question (indent another level or non global subroutine or anonymous or sub _private_by_convention)
by Anonymous Monk on Jul 31, 2014 at 07:39 UTC

      I didn't know that underscores were the convention for module code that should not be used outside the module. Now I do. That seems like the best good solution to my problem given the module code is already indented annoyingly far.

      I'm glad I asked this, the answers here have been very helpful. I'll come up with more descriptive node names in future.

Re: Code reuse question
by Athanasius (Archbishop) on Jul 31, 2014 at 07:53 UTC

    Anonymous Monk’s approach — prefix your sub’s name with an underscore and rely on the convention that subs so-named are to be treated as private — is likely the simplest and most convenient solution. But yes, an anonymous subroutine will give you what you want if you keep the (only) reference to it in a lexical variable:

    package MyModule; my $sub = sub { ... }; $sub->() for 1 .. 2; # call the sub twice

    However, this seems like overkill if you will really only call the subroutine twice. In that case, “just wrap it in another loop” and prevent the code from “disappear[ing] off the right of [your] screen” by re-formatting the code (splitting long lines). This is generally a good idea anyway as it makes the code easier to read (and to annotate with comments).

    Hope that helps,

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

Re: Code reuse question (managing module-internal subroutines)
by graff (Chancellor) on Jul 31, 2014 at 08:23 UTC
    Anonymous Monk has given sensible suggestions, but I'll add to that (including, I hope, a better mod on the thread title).

    I don't use 5.18 yet, so I'm not sure about this "lexical sub" you speak of, but with older versions, I think there's a "morally equivalent" approach that might have the properties that you're looking for. The following works for me in 5.12 (and presumably works in any Perl 5):

    # TryMe.pm package TryMe; use strict; use warnings; sub new { my %obj = ( name => "TryMe", purpose => "None that I know of" ); return bless \%obj; } sub do_something { my ( $class, $with_something ) = @_; my $special_trick = sub { "... this is only a test " }; my $return_value = "Here's how I do_something $with_something:\n"; for ( 1 .. 3 ) { $return_value .= &$special_trick; } $return_value; } 1;
    Note how I assign an anonymous sub to a lexically scoped variable. Here's a simple use case:
    #!/usr/bin/perl use strict; use warnings; use TryMe; my $tester = TryMe->new(); print $tester->do_something( "nice" ), "\n";
Re: Indent, anonymous sub, or lexical sub for module private code?
by Laurent_R (Canon) on Aug 01, 2014 at 06:39 UTC
    I quite regularly write subs that are called only once (e.g. to read a param file and load it into a param hash). Granted, it does not look quite right if you consider that the main point of a sub is to avoid code duplication (the DRY principle), but it is still better IMHO than having hundreds of code lines in the main section of the program. Having a sub to isolate parts of the program that have a well defined purpose is perfectly legitimate in my view, even if called only once (or twice).

    Otherwise, if you really want your function to be private, then use an anonymous sub. If not, the leading underscore convention should be sufficient (you can also use caller to check that the sub is called by only another specific function and no other, but that's seems to be overkill in most cases).

      Granted, it does not look quite right if you consider that the main point of a sub is to avoid code duplication (the DRY principle), but it is still better IMHO than having hundreds of cole lines in the main section of the program. Haqving a sub to isolate part of the program that have a well defined purpose if perfectly legitimate in my view, even if called only once (or twice).

      I wholeheartedly agree. Although code reuse is an important motivation for subroutines, it's not the only one: it's equally important to be able to break up a program into smaller pieces that carry out a specific task. This makes it easier for the developer to understand the program: each individual subroutine will be easier to digest by virtue of its smaller size, and the main program will be written in a more abstract fashion, allowing the developer to focus on the bigger picture without constantly getting bogged down in details.

      I sometimes think of the developer as the general commanding an army, and the tools the language provides as the individual foot soldiers. Subroutines are the ranks in between, officers and NCOs, allowing the general to say e.g. "fortify this position" without having to care about how exactly this is accomplished (by building trenches), or how trenches are built (by having the foot soldiers dig), or indeed about picking up a spade and moving soil from here to there.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1095687]
Approved by graff
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: (4)
As of 2024-04-18 04:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found