Using element references in @_ to avoid code duplication

Is it safe to refer to @_ elements in a routine to avoid code duplication? I also wonder if the following practice is good practice or can be simplified. I have a mod_str routine that takes an option, saying that the string argument should be changed in place or not:

 use feature qw(say); use strict; use warnings; my $str = 'abc'; my $mstr = mod_str( $str, in_place => 0 ); say $mstr; mod_str( $str, in_place => 1 ); say $str; sub mod_str { my %opt; %opt = @_[1..$#_]; if ( $opt{in_place} ) { $_[0] =~ s/a/A/g; # .. do more stuff with $_[0] return; } else { my $str = $_[0]; $str =~ s/a/A/g; # .. do more stuff with $str return $str; } } 

To avoid repeating / duplicating code in the if and else blocks above, I tried to improve mod_str :

 sub mod_str { my %opt; %opt = @_[1..$#_]; my $ref; my $str; if ( $opt{in_place} ) { $ref = \$_[0]; } else { $str = $_[0]; # make copy $ref = \$str; } $$ref =~ s/a/A/g; # .. do more stuff with $$ref $opt{in_place} ? return : return $$ref; } 
+7
perl
source share
2 answers

The in-place flag changes the functional interface to the point where the new function should be. This will simplify the interface, testing, documentation, and internal functions to have two functions. Instead of parsing the arguments and having a large if / else block, the user has already made this choice for you.

Another way to look at this is the in_place parameter in_place always be set to a constant. Since it fundamentally changes the behavior of the function, there is no reasonable case when you write in_place => $flag .

Once you do this, reuse will become more apparent. Write one function to perform the operation. Write another that calls it on the copy.

 sub mod_str_in_place { # ...Do work on $_[0]... return; } sub mod_str { my $str = $_[0]; # string is copied mod_str_in_place($str); return $str; } 
+8
source share

In the absence of the disgraced given I like to use for as a localizer. These are effectively aliases $_ or $_[0] , or a local copy depending on the value of the in_place hash element. It is directly comparable to your $ref , but with aliases and much cleaner.

I see no reason to return a useless undef / () if the string is changed in place; a routine can also return a new value for a string. (I suspect that the old value may be more useful after the $x++ mod, but that makes the code uglier!)

I'm not sure if this is readable code for anyone other than me, so comments are welcome!

 use strict; use warnings; my $ss = 'abcabc'; printf "%s %s\n", mod_str($ss), $ss; $ss = 'abcabc'; printf "%s %s\n", mod_str($ss, in_place => 1), $ss; sub mod_str { my ($copy, %opt) = @_; for ( $opt{in_place} ? $_[0] : $copy ) { s/a/A/g; # .. do more stuff with $_ return $_; } } 

Exit

 AbcAbc abcabc AbcAbc AbcAbc 
+5
source share

All Articles