Re: Can a large subroutine be split in two (e.g. parent and child relationship)? (don't just split)
by tye (Sage) on Jul 05, 2006 at 21:03 UTC
|
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.
| [reply] |
Re: Can a large subroutine be split in two (e.g. parent and child relationship)?
by Zaxo (Archbishop) on Jul 05, 2006 at 21:09 UTC
|
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.
| [reply] |
Re: Can a large subroutine be split in two (e.g. parent and child relationship)?
by GrandFather (Saint) on Jul 05, 2006 at 20:50 UTC
|
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.
DWIM is Perl's answer to Gödel
| [reply] [d/l] |
Re: Can a large subroutine be split in two (e.g. parent and child relationship)
by Hue-Bond (Priest) on Jul 05, 2006 at 20:44 UTC
|
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]
}
}
| [reply] [d/l] [select] |
|
|
use strict;
use warnings;
{
my ($var1, $var2, $var3, @arr1);
sub foo {
bar();
}
sub bar {
++$var1;
print "$var1\n";
}
}
foo ();
foo ();
Prints:
1
2
DWIM is Perl's answer to Gödel
| [reply] [d/l] [select] |
|
|
| [reply] |
Re: Can a large subroutine be split in two (e.g. parent and child relationship)?
by Ieronim (Friar) on Jul 05, 2006 at 21:01 UTC
|
You can use a reference to a anonymous sub inside your big subroutine. For example, in this script the 'my' variables from the outer subroutine are visible inside $inner:
#!/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. | [reply] [d/l] [select] |
Re: Can a large subroutine be split in two (e.g. parent and child relationship)?
by jdporter (Paladin) on Jul 05, 2006 at 20:41 UTC
|
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.
We're building the house of the future together.
| [reply] |
Re: Can a large subroutine be split in two (e.g. parent and child relationship)?
by betterworld (Curate) on Jul 05, 2006 at 22:03 UTC
|
Alternatively, you could get an editor which supports folding.
In vim you could do it like this:
sub foo {
# {{{ variables
my ($var1, $var2);
# }}}
# {{{ actions
bar($var1, $var2) until $var1;
# }}}
}
# vim: set foldmethod=marker:
| [reply] [d/l] |
Re: Can a large subroutine be split in two (e.g. parent and child relationship)?
by derby (Abbot) on Jul 05, 2006 at 22:07 UTC
|
| [reply] |
|
|
Thanks all. You've given me something to work with and consider.
| [reply] |