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

Hi monks,

I am writing a very simple sub-routine with one array and one scalar as the input. The problem is that i can't see the value of the scalar within the subroutine. Where am i going wrong?

my $name1="chrom1 unique"; print "NAME1 $name1\n"; cog_class(@c1_uniq_cog_ids, $name1); + + sub cog_class { + + my (@c1_uniq_cog_ids, $name) = @_; # DOESN'T WORK BELOW! print "NAME $name\n"; + + for (my $i=0; $i<@c1_uniq_cog_ids; $i++) { # BLAH BLAH } + + }

Replies are listed 'Best First'.
Re: subroutine arguments
by mulander (Monk) on Oct 25, 2005 at 11:14 UTC
    You do not see the single scalar because all arguments passed into a subrutine are flatened into a list. So when you call your sub cog_class(@somearray, $somescalar); the $somescalar variable and @somearray all became @_ in the subrutine.

    If you only need one array and one scalar just switch them places cog_class($somescalar,@somearray); and if you need more complex data structures unchanged I suggest passing it by reference.

    And another thing, you can't use those scalars by name in the sub unless you take them out of @_, you can do it like this:
    #!/usr/bin/perl use warnings; use strict; my $scalar = 'a'; my @array = qw(1 2 3); some_sub($scalar,@array); sub some_sub { my $scalar = shift; # take the first element out of @_ # and the first element in this case is $scalar with 'a' # inside my @array = @_; # pass all the remaining arguments into # @array so it now contains 1,2,3 }
    I suggest that you read more about subrutines in the:
    perldoc perlsub
Re: subroutine arguments
by McDarren (Abbot) on Oct 25, 2005 at 11:22 UTC
    Try passing the list as a reference, for example:
    cog_class(\@c1_uniq_cog_ids, $name1);
    Then, shift off the list within the function, like so:
    my $c1_uniq_cog_ids = shift; my $name = shift;
    So you finish up with something like:
    #!/usr/bin/perl -w use strict; my $name1="chrom1 unique"; my @c1_uniq_cog_ids = qw(1 2 3 4 5); print "NAME1 $name1\n"; cog_class(\@c1_uniq_cog_ids, $name1); sub cog_class { my $c1_uniq_cog_ids = shift; my $name = shift; print "NAME $name\n"; for my $id ( @{$cog_ids_ref} ){ # BLAH BLAH } }
    Update:
    Oh, one more thing... that C-style for loop that you have is probably better written either as:
    foreach my $id (@{c1_uniq_cog_ids}) { # Do stuff }

    or even....
    for (@{c1_uniq_cog_ids}) { # Do stuff }
    Update 2: Fixed, as pointed out by [id://cbrandtbuffalo]
    hope this helps

    --Darren
      I'm not sure your example will completely work as shown. The first shift in your sub will pull off a reference to the array, not the array itself. So the sub should look something like:
      sub cog_class { my $cog_ids_ref = shift; my $name = shift; print "NAME $name\n"; for my $id ( @{$cog_ids_ref} ){ # BLAH BLAH } }
      Try passing the list as a reference ... Then, shift off the list

      I don't mean to sound petty, but in situations like this it's especially important to be mindful of the difference between an array and a list. You can't take a reference to a list. It's an array reference.

Re: subroutine arguments
by blazar (Canon) on Oct 25, 2005 at 11:12 UTC
    The array slurps everithing in the assignment. This is one of the cases in which prototypes may come handy. Check perlsub to learn more about them.
    sub cog_class (\@$) { my $name = pop; print "NAME $name\n"; for (@{ $_[0] }) { # Note the Perl-style c<for> loop!! # BLAH BLAH } }
    Or else, even avoiding to mess up with prototypes (if you don't really need them), you must extract the single scalar params you want manually.
Re: subroutine arguments
by murugu (Curate) on Oct 25, 2005 at 12:13 UTC

    The problem here is the array @c1_uniq_cog_ids and the scalar variable $name1 have got flattened and will be stored in the variable @c1_uniq_cog_ids inside your subroutine. So inorder to retain the values you need to pass the array as reference.

    cog_class(\@c1_uniq_cog_ids, $name1); sub cog_class { + my ($c1_uniq_cog_ids, $name) = @_; ### you can use @$c1_uniq_cog_ids to get the contents array }

    In your case even you can reverse the way in which your parameters are passed.

    cog_class($name1,@c1_uniq_cog_ids); sub cog_class { my ($name,@c1_uniq_cog_ids)=@_; }

    Hope this may shed some light....

    Regards,
    Murugesan Kandasamy
    use perl (;;);