Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of reference to elements in @_ to avoid duplicating code

Tags:

perl

Is it safe to take reference of elements of @_ in a subroutine in order to avoid duplicating code? I also wonder if the following is good practice or can be simplified. I have a subroutine mod_str that takes an option saying if a string argument should be modified 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;
    }
}

In order 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;
}
like image 668
Håkon Hægland Avatar asked Aug 08 '15 20:08

Håkon Hægland


People also ask

What is ref reference?

The ref keyword indicates that a variable is a reference, or an alias for another object. It's used in five different contexts: In a method signature and in a method call, to pass an argument to a method by reference.

How do references work in C++?

The main use of references is acting as function formal parameters to support pass-by-reference. In an reference variable is passed into a function, the function works on the original copy (instead of a clone copy in pass-by-value). Changes inside the function are reflected outside the function.

What is a reference in C#?

In C#, classes and interfaces are reference types. Variables of reference types store references to their data (objects) in memory, and they do not contain the data itself. An object of type Object , string , or dynamic is also a reference type.

What is reference variable What is its major use?

A reference variable is a variable that points to an object of a given class, letting you access the value of an object. An object is a compound data structure that holds values that you can manipulate. A reference variable does not store its own values.


2 Answers

The "in place" flag changes the function's interface to the point where it should be a new function. It will simplify the interface, testing, documentation and the internals to have two functions. Rather than having to parse arguments and have a big if/else block, the user has already made that choice for you.

Another way to look at it is the in_place option will always be set to a constant. Because it fundamentally changes how the function behaves, there's no sensible case where you'd write in_place => $flag.

Once you do that, the reuse becomes more obvious. Write one function to do the operation in place. Write another which calls that on a 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;
}
like image 75
Schwern Avatar answered Nov 04 '22 03:11

Schwern


In the absence of the disgraced given I like using for as a topicalizer. This effectively aliases $_ to either $_[0] or the local copy depending on the value of the in_place hash element. It's directly comparable to your $ref but with aliases, and a lot cleaner

I see no reason to return a useless undef / () in the case that the string is modified in place; the subroutine may as well return the new value of the string. (I suspect the old value might be more useful, after the fashion of $x++, but that makes for uglier code!)

I'm not sure whether this is readable code to anyone but 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 $_;
    }
}

output

AbcAbc abcabc
AbcAbc AbcAbc
like image 35
Borodin Avatar answered Nov 04 '22 03:11

Borodin