in reply to Scalar and void subroutines

You could avoid some duplication by using the following syntax:

sub name { my $arg = ref $_[0] ? $_[0] : \do{my $anon = $_[0]}; # Do stuff. $$arg =~ s/^un//; return $$arg; }

or using an alias instead of a reference:

sub name { our $arg; local *arg = ref($_[0]) ? $_[0] : \do{my $anon = $_[0]}; # Do stuff. $arg =~ s/^un//; return $arg; }

Test code:

$i = $j = 'unchanged'; name(\$i); print("i:$i\n"); # i:changed $i = $j = 'unchanged'; $j = name($i); print("i:$i, j:$j\n"); # i:unchanged, j:changed $i = $j = 'unchanged'; $j = name(\$i); print("i:$i, j:$j\n"); # i:changed, j:changed

You could also check the calling context and avoid reference altogether:

sub name { our $arg; local *arg = defined wantarray ? \do{my $anon = $_[0]} : \$_[0]; # Do stuff. $arg =~ s/^un//; return $arg; }

but I'd avoid that since the it's not obvious what's going to happen when reading the call:

name($i); # In place $j = name($i); # Not in place sub test { name($_[0]) } # unknown!!! sub test { name($_[0]) } test($i); # In place sub test { name($_[0]) } $j = test($i); # Not in place

Update: Showed why wantarray is a bad idea instead of just saying it is.

Update: Fixed bug found by eff_i_g. That'll teach me to test without warnings.

Update: Oops, I forgot I should be able to read the argument, not just write to it. Fixed by changing \do{my ...} to \do{my ... = $_[0]}.

Replies are listed 'Best First'.
Re^2: Scalar and void subroutines
by eff_i_g (Curate) on Nov 10, 2005 at 21:36 UTC
    ike:

    The return here errors if called as: name(\$var)
    sub name { my ($arg) = @_; if (not ref $arg) { $arg = \$arg; } # Do stuff. $$arg = 'changed'; return $$arg; }
    If I remove the return $$arg; it still works in either context because of that sneaky little 'return the last value' trick :D

    Thanks!
Re^2: Scalar and void subroutines
by eff_i_g (Curate) on Nov 10, 2005 at 22:54 UTC
    I had a problem with the previous sub (when calling it in scalar context and not passing a reference). I was able to get the following to work:
    sub name { #%% reference argument if it is not a reference my $string = ref $_[0] ? $_[0] : \$_[0]; # processing #%% use return caveat $$string; }

      That's no good either. It clobbers $i in $j = name($i);.

      The fix is to change \do{my ...} to \do{my ... = $_[0]} in my subs. (Just fixed in grandparent.)

        Ahh. I see that you had that. Thanks. :)