Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Refactoring: sub within a sub

by temporal (Pilgrim)
on Jul 25, 2012 at 19:29 UTC ( [id://983723]=perlquestion: print w/replies, xml ) Need Help??

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

I am cleaning up some scripts and ended up pulling an entire script with its subroutines into another script - as a subroutine. Something like:

use strict; sub external { my $foo = some_op(); sub sub_of_sub { print $foo; } }

Like in the example, I have to keep these subroutines in scope so that some variables that are defined in the outer subroutine are available.

I don't want to make these variables global. I have a lot going into this script and I'm trying to keep things organized. I want all of my globals to be things that are used by more than one subroutine.

Some more background:

Essentially, I am writing a module that contains a collection of 'tasks'. A superscript to this one will be importing and calling these tasks individually and for different times, triggers, etc. This is one module of many. Each module will contain the same 'tasks' (same named subroutines) such that my superscript can iterate through them all easily.

Anyway, I checked out Defining a sub within a sub: OK?, but I'm not sure if it exactly answers my question. Why are anonymous subs more acceptable? I just want to get some feedback/suggestions since this seems like something that might be considered... poor Perl form.

Replies are listed 'Best First'.
Re: Refactoring: sub within a sub
by GrandFather (Saint) on Jul 25, 2012 at 23:41 UTC

    Most likely a better solution would be to use object oriented techniques. Define an "interface" (methods that are expected to be supplied by an object) then have each of your "worker" modules register themselves when they are loaded by pushing a worker object into a list. Something like:

    use strict; use warnings; our @Workers; package Worker1; push @Workers, Worker1->new(); sub new { return bless {}, __PACKAGE__; } sub doStuff { print __PACKAGE__ . " reporting for duty\n"; } package Worker2; push @Workers, Worker2->new(); sub new { return bless {}, __PACKAGE__; } sub doStuff { print __PACKAGE__ . " standing by\n"; } package main; for my $worker (@Workers) { $worker->doStuff(); }

    Prints:

    Worker1 reporting for duty Worker2 standing by

    In practise each package would be in a different module file. Now each worker object keeps its own state so globals aren't needed.

    True laziness is hard work
Re: Refactoring: sub within a sub
by moritz (Cardinal) on Jul 25, 2012 at 19:38 UTC
    Why are anonymous subs more acceptable?

    Since subs are package-scoped in Perl 5, the inner subs are visible from the outside. Which means that they are visible before the outer sub is run, which is why they can't easily be a closure over the variables from the outer sub.

    Which is why anonymous subroutines are safer in this case.

Re: Refactoring: sub within a sub
by tobyink (Canon) on Jul 25, 2012 at 19:44 UTC
    use strict; use Digest::SHA 'sha1_hex'; sub get_hash_printer { my $str = shift; my $hash = sha1_hex($str); return sub { print "$hash\n"; } } my $hash_printer = get_hash_printer("Hello"); $hash_printer->(); __END__ f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Refactoring: sub within a sub
by temporal (Pilgrim) on Jul 25, 2012 at 20:56 UTC

    Hm, okay that makes sense. I will probably be fine implementing it like this then. Just wanted to know if there were any major pitfalls or get some insight into an alternative implementation.

    Strange things are afoot at the Circle-K.

      The major pitfall is that, if you ever call the outer sub more than once per process, then the inner sub will not be sharing any lexicals defined within the outer sub, hence the "won't stay shared" warning. So be sure to enable warnings.

      - tye        

Re: Refactoring: sub within a sub
by Anonymous Monk on Jul 26, 2012 at 06:51 UTC

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2024-04-23 06:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found