Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Parameter passing

by Anonymous Monk
on Oct 30, 2003 at 15:14 UTC ( [id://303274]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to have a sub that returns success or failure on completion. I'd like the sub to take parameters, make changes to those parameters and pass the changed parameters back to the caller for use in the main body. What it the correct way to do it in Perl? Thanks.
my ($x, $y); if (fn(\$x, \$y)) { die "fn() failed\n"; } # do stuff with $x and $y... exit 0; sub fn { my ($fn_x, $fn_y) = @_; ($fn_x, $fn_y) = ('x', 'y'); my $rc = 0; $rc = 1 if $fn_x ne 'x'; # never happens, just an example return 0; }

Replies are listed 'Best First'.
Re: Parameter passing
by gjb (Vicar) on Oct 30, 2003 at 15:23 UTC

    Almost right,

    sub fn { my ($fn_x, $fn_y) = @_; ($$fn_x, $$fn_y) = ('x', 'y'); my $rc = 0; $rc = 1 if $$fn_x ne 'x'; return 0; }
    is what you want though. The references $fn_x and $fn_y should be dereferenced if you want to access/change the values they refer to. For a scalar, dereferencing is done with $, while @, % and & are used to dereference lists, hashes and functions respectively. E.g. suppose that $r_list is a reference to a list, you'd get the list it refers to using @$r_list while you'd get the second element of the list using $r_list->[1].

    For the ocmplete story, have a look at perlref.

    Incidently, you might want to die inside the function fn since this is where the exception actually occurs. The if statement can be replaced by eval {...}; and you can test for an error by checking the value of the variable $@.

    Hope this helps, -gjb-

Re: Parameter passing
by monktim (Friar) on Oct 30, 2003 at 15:21 UTC
    You didn't dereferece your references. Change the code to:
    ($$fn_x, $$fn_y) = ('x', 'y');
    That should fix your problem.
Re: Parameter passing
by TomDLux (Vicar) on Oct 30, 2003 at 15:44 UTC

    I have a feeling you intended to return $rc.

    If your routine is called from various places and should only die in certain instances, have the die at the outer level, but if it always enforces that special condition, you can have the die insided the routine.

    I would suggest having a routine just for the test and the die; I would name it something like die_unless_value_is_x.

    Update:If you really need to have references to scalar parameters, that's the idea situation for fuunction prototypes:

    sub fn (\$\$) { ... } fn $x, $y;

    You declare the fn() takes references to scalars, and then don't need to escape the variables when you invoke the function. Of course, poorly used, this can also lead to confusion ... Why is this variable modified in the routine?

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

Re: Parameter passing
by meetraz (Hermit) on Oct 30, 2003 at 20:43 UTC
    Just to propose a TMTOWTDI solution that nobody else suggested yet..

    Variables passed to a subroutine are automatically aliased to the @_ array, so if you modify them, you modify the original variables passed in:

    use strict; my ($X, $Y); modifyvars($X, $Y); print "after: X=$X, Y=$Y\n"; sub modifyvars { $_[0] = 'foo'; $_[1] = 'bar'; my $rc = 0; $rc = 1 if $_[0] ne 'x'; return 0; }
    Though this isn't too easy to read. Using prototypes (mentioned above) is better.
Re: Parameter passing
by hmerrill (Friar) on Oct 30, 2003 at 15:54 UTC
    Why pass references in - why not just pass the scalars $x and $y?
    my ($x, $y); if (fn($x, $y)) { die "fn() failed\n"; } # do stuff with $x and $y... exit 0; sub fn { my ($fn_x, $fn_y) = @_; ($fn_x, $fn_y) = ('x', 'y'); my $rc = 0; $rc = 1 if $fn_x ne 'x'; # never happens, just an example return 0; }
    The only change I made was to change the call - instead of passing references in, just pass the scalars. You aren't changing the values of the variables in the subroutine - I can't see any reason why you would want to pass the references instead of the actual scalar values.

      Try running this:

      #!/usr/bin/perl use strict; my $a = 2; f($a); print "$a\n"; sub f { my $x = shift; $x = 5; }
      You'll notice it prints '2', while according to you it should print '5'.

      This is precisely why a reference should be passed to the function. If you don't, you actually pass a value (2) and initialize the local variable $x to it. Later in the sub the value of $x is change to 5. Now why should that change the value of $a in the main program? It shouldn't since the subroutine only knows about the value of $a which happens to be 2, not about $a itself so the value of $a will remain 2 as it was before the function call.

      Changing the code above to:

      #!/usr/bin/perl use strict; my $a = 2; f(\$a); print "$a\n"; sub f { my $x = shift; $$x = 5; }
      will actually print '5' rather than '2'. Now you pass the address of the variable $a to the sub and it gets stored in $x. The value at the address in $x is set to 5 by dereferencing $x with $$x. Since $x is the address of $a, it's value is indeed changed to 5.

      Hope this helps, -gjb-

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://303274]
Approved by BazB
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (2)
As of 2024-04-19 21:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found