gonfer
gonfer

Reputation: 33

Perl: Modify variable passed as param to subroutine

I need to modify a variable inside a routine, so it keeps the changes after leaving the routine. Here's an example:

$text = "hello";
&convert_to_uppercase($text);
print $text;

I want to see "HELLO" on the screen, not "hello".

The routine would be:

sub convert_to_uppercase($text){
  <something like $text = uc($text);>
}

I know how to do it in PHP, but it seems that the parameters are not changed the same way. And, I've been searching everywhere and I couldn't find a concrete answer.

Upvotes: 3

Views: 6672

Answers (2)

Borodin
Borodin

Reputation: 126762

You really shouldn't use an ampersand & when calling a Perl subroutine. It is necessary only when treating the code as a data item, for instance when taking a reference, like \&convert_to_uppercase. Using it in a call hasn't been necessary since version 4 of Perl 5, and it does some arcane things that you probably don't want.

It is unusual for subroutines to modify their parameters, but the elements of @_ are aliases of the actual parameters so you can do what you ask by modifying that array.

If you write your subroutine like this

sub convert_to_uppercase {
    $_[0] = uc $_[0];
}

then it will do what you ask. But it is generally best to return the modified value so that the decision on whether to overwrite the original value can be taken by the calling code. For instance, if I have

sub upper_case {
    uc shift;
}

then it can be called either as

my $text = "hello"; 
$text = upper_case($text);
print $text;

which does as you require, and modifies $text; or as

my $text = "hello";
print upper_case($text);

which leaves $text unchanged, but returns the altered value.

Upvotes: 7

Shawn Darichuk
Shawn Darichuk

Reputation: 390

Passing a reference and modifying the original variable inside the subroutine would be done like this:

$text = 'hello';
convert_to_uppercase(\$text);  #notice the \ before $text
print $text;

sub convert_to_uppercase {       #perl doesn't specify arguments here

    ### arguments will be in @_, so @_ is now a list like ('hello') 
    my $ref = shift;             #$ref is NOT 'hello'. it's '$text'

    ### add some output so you can see what's going on:
    print 'Variable $ref is: ', $ref, " \n";  #will print some hex number like SCALAR(0xad1d2)
    print 'Variable ${$ref} is: ', ${$ref}, " \n"; #will print 'hello'

    # Now do what this function is supposed to do:
    ${$ref} = uc ${$ref};  #it's modifying the original variable, not a copy of it
}

The other way is to create a return value inside the subroutine and modify the variable outside of the subroutine:

$text = 'hello';
$text = convert_to_uppercase($text);  #there's no \ this time
print $text;

sub convert_to_uppercase {
    # @_ contains 'hello'
    my $input = shift;    #$input is 'hello'
    return uc $input;    #returns 'HELLO'
}

But the convert_to_uppercase routine seems redundant because that's what uc does. Skip all of that and just do this:

$text = 'hello';
$text = uc $text;

Upvotes: 6

Related Questions