3

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.

3
  • This question might help: stackoverflow.com/questions/24063638/… Commented Oct 16, 2014 at 22:21
  • Thanks a lot! My new question is: why ($x1, $y1) = @_;? Would it be the same if i did: $x1 = $_[0]; $y1 = $_[1];? Please consider I'm really new to Perl, and thanks for your patience! Commented Oct 16, 2014 at 23:14
  • Yes it is. ($x1, $y1) = @_; is a shortcut. Commented Oct 16, 2014 at 23:27

2 Answers 2

7

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Great! One more thing: isn't it necessary to declare the routine signature? I see you do sub convert_to_uppercase{} instead of sub convert_to_uppercase($text){} but when you call it, you do convert_to_uppercase($text). Another thing, I used the & because I didn't know I shouldn't, I'm really new to Perl. What I'm doing is a validation from user input, so I want to uppercase the input from the user (I'll check it later too), and return a 1 or a 0 if valid or not, that's why I don't use the the return to do this. You were really helpful, thanks a lot!
@gonfer, no. Sub signatures have only been added as a core Perl feature since Perl 5.20 (which came out a few months ago), and only experimentally. (Though there are several implementations of signatures available as extension modules of varying levels of stability.)
6

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;

3 Comments

Hello, you cleared out all my doubts! As I replied the other guy, I'm validating a key entered by the user. I want to uppercase it AND validate it, and leave it in upper case for future checks. If it's valid, I'll return 1, otherwise 0. A simple uc would be easier, but I wanted to do all this inside a single routine. Thanks a lot to you too. I'm amused by the quality and speed of the replies here.
One moe thing now I read you reply again: modifying the @_, the variable is changed outside the routine, but is it necessary to pass it with the \ when calling the subroutine? This way, the $ref is an actual reference to the variable, and you de-reference it with the {}. The use of {} is only when you pass the parameter with the \? Thanks!
It's worth telling that you can use convert_to_uppercase($text); (without "\" before the subroutine parameter) instead of convert_to_uppercase(\$text); by adding "\" before shift: my $ref = \shift;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.