2
\$\begingroup\$

Is the subroutine test1 ugly?/uglier than the others?

#!/usr/bin/env perl
use warnings;
use strict;
use 5.10.1;
use Data::Dumper;

my $ref = { one => 1, two => 2, three => 3 };


sub test1 {
    my ( $ref ) = @_;
    $ref->{three} = 4;
}
test1( $ref );

sub test2 {
    $ref->{three} = 4;
}
test2( $ref );

sub test3 {
    my ( $ref ) = @_;
    $ref->{three} = 4;
    return $ref;
}
$ref = test3( $ref );


say Dumper $ref;
\$\endgroup\$
2
  • 3
    \$\begingroup\$ The argument in test2( $ref ); is ignored. \$\endgroup\$
    – aschepler
    Feb 19, 2013 at 15:18
  • 1
    \$\begingroup\$ @HunterMcMillen I had not thought of it. \$\endgroup\$
    – sid_com
    Feb 19, 2013 at 17:04

1 Answer 1

8
\$\begingroup\$

Here are some considerations when writing such functions:

  • By passing the function all of the variables it needs (test1), you don't need to rely on global variables. This makes the function easier to test, more predictable (no side effects) and easier to refactor as you can move it to another module or file easily. If it relied on global variables, it would be broken if the variable is moved or its data structures changed.

  • Returning the original reference is not necessary for test3, because the original $ref is changed. Returning is useful if you want to chain function calls.

  • Modifying the arguments passed your function directly can be surprising to the function's caller. If you do this, make it clear in the documentation. If you actually want to make a new copy of the object, modify it and return it, use something like Clone. Of course, this can be slow.

  • Just in case you are writing object accessors/mutators: please consider using a module such as Class::Accessor or the more heavyweight but extensive Moose which can generate such functions for you automatically.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.