Goal: Within a package, to take a large subroutine and remove a chunk of code that includes 'my' declarations (which before the split are the "parent's" "my's") and put it into a separate subroutine ('child', if there is such a thing) for easier reading of the code. This chunk of code has a single purpose.
Is that possible with ease? If so, 'how'? Must more declarations be made in order for the 'parent' subroutine to see the 'child' subroutine and all of the variables (and vice versa)?
Hope this makes sense... :)
Thanks in advance.
It's possible to do the sort of "refactoring" that you're talking about, but it might not be as simple as you're hoping; it really depends on what variables need to be seen by both routines and how they'll be used. If you show the routine you're trying to split, or one similar to it in essential respects, we can take a hack at it.
If I'm understanding it right, you have something like this:
sub foo {
my ($var1, $var2, $var3, @arr1);
[a large pile of code]
}
And you vant to split that code in two smaller subs but are worried about variable scoping and so. What about this?
{
my ($var1, $var2, $var3, @arr1);
sub foo {
[some code]
bar();
}
sub bar {
[rest of the code]
}
}
--
David Serrano
That creates a closure on the variables which is different behaviour than having the variables local to $foo. Consider:
use strict;
use warnings;
{
my ($var1, $var2, $var3, @arr1);
sub foo {
bar();
}
sub bar {
++$var1;
print "$var1\n";
}
}
foo ();
foo ();
Prints:
1 2
That creates a closure on the variables
It was intended but now I realize that I didn't take into account the outcome you are showing.
--
David Serrano
Generally if you do something like that you need to pass the parent's variables into the child sub. If the parent sub needs to see changes in the variables then you need to pass references to the variables into the child sub. At that point all the references to the pass by reference variables in the child sub need to be adjusted. Consider:
sub parent {
my $valueOnly;
my $needsUpdates;
child ($valueOnly, \$needsUpdates);
}
sub child {
my ($valueOnly, $needsUpdates) = @_;
$$needsUpdate = $valueOnly; # was: $needsUpdate = $valueOnly;
}
Notice the second $ prepended to $needsUpdate to dereference it in the child sub.
#!/usr/bin/perl
print outer('John', qw/dog car home/), "\n";
sub outer {
my $name = shift;
my @items = @_;
my $inner = sub {
return "$name\'s $_[0] ";
};
return map {$inner->($_)} @items;
}
The example is quite silly, but i often use this technique to simplify code. It is useful, if $inner has no sense outside outer.
It usually works much better to factor out logically coherent parts into well-named subroutines that, due to being logically coherent, don't need to have a lot of information passed in and out. It is called "refactoring" and can usually make code not just easier to read but also less buggy and easier to maintain. The goals include increasing "good properties" of the code such as modularity, loose coupling, data hiding, etc.
- tye
Sure it can, if it has a single purpose you can put a name to.
To do that with ease, you can refine the big function bit by bit. Make sure that it doesn't assign to global variables, unless that's its sole purpose. Try to make the function return what it produces, getting all of its information from its arguments. That insulates the rest of the application from the functions' workings.
Now start cutting down big lists of initial my declarations, moving each lexical variable's declaration to where it is first assigned. Then move that assignment down to just before it is first used. Find where each variable is last used, and consider that spot for the end of a lexical block. The block which most closely corresponds to the new function you're thinking of will be the body of your new function. It will tell you which outer variables correspond to arguments of the new function, and which are internal to it.
This whole process is referred to as "refactoring", and it's worth the exercise to do it.
After Compline,
Zaxo
sub foo {
# {{{ variables
my ($var1, $var2);
# }}}
# {{{ actions
bar($var1, $var2) until $var1;
# }}}
}
# vim: set foldmethod=marker:
In a word - yes (depending on your definition of 'with ease').
perlmonks.org content © perlmonks.org and betterworld, derby, GrandFather, Hue-Bond, Ieronim, jdporter, newbie00, tye, Zaxo
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03