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

UPDATE: Issue fixed thanks to replies. Resolved. I'm having trouble writing to an array passed to a subroutine by reference.
#!/usr/bin/perl -w use strict; sub main { my @broken; my $location = "/home/user/"; find_broken_links( $location, \@broken ); foreach my $var (@broken) { print "Returned: $var\n"; } } sub find_broken_links { my $location = ( defined $_[0] ) ? "$_[0]" : return ; my $broken_links = ( defined $_[1] ) ? "$_[1]" : return ; ... # other code not shown here push @$broken_links, $var; ... }

Can't use string ("ARRAY(0x1be9360)") as an ARRAY ref while "strict refs" in use at script.pl line ## some number ##
Any help please?

Replies are listed 'Best First'.
Re: Modifying Arrays passed by reference to subroutine
by AnomalousMonk (Archbishop) on Jun 09, 2009 at 03:55 UTC
    You correctly pass an array reference to the function  find_broken_links, but then within the function you stringize the reference
        my $broken_links = ( defined $_[1] ) ? "$_[1]" : return ;
    before assigning it to a variable. This renders the reference useless as a reference.

    The solution: don't do that:
        my $broken_links = ( defined $_[1] ) ? $_[1] : return ;

    In addition, my own personal preference is to separate argument assignment and validation within a function rather than trying to bury them both in a single statement. I feel it leads to more readable and maintainable code.

    sub find_broken_links { my ($location, $broken_links, ) = @_; return unless defined($location) and defined($broken_links); ... do stuff ... push @$broken_links, 'stuff'; return; }
    Update: BTW, kudos for using strictures and (I hope) warnings.
Re: Modifying Arrays passed by reference to subroutine
by Marshall (Canon) on Jun 09, 2009 at 04:04 UTC
    You are very close! First enable run time warnings (the -w flag) and use strict (first 2 lines of code below). There is no sub called main{} in a Perl program this is not Java. I wouldn't put these checks for undef input parameters. The runtime warnings will show error if that happens. Basically have have the right idea and your code runs!
    #!/usr/bin/perl -w use strict; my @broken = (1,2,3); my $location = "/home/user/"; find_broken_links( $location, \@broken ); foreach my $var (@broken) { print "Returned: $var\n"; } sub find_broken_links { my ($location, $broken_links) = @_; # other code not shown here my $var ='X'; push @$broken_links, $var; } #prints: #Returned: 1 #Returned: 2 #Returned: 3 #Returned: X
    Update:I see some other posts while I was writing mine. The "stringification" as AnomalousMonk points out is a problem. The code I wrote just automatically didn't have that condition and so it worked. I would caution against this type of "silent program error". These sub input params will be undefined if there is an error in the calling program. If that is the case, you want to know about it! Otherwise your code would just simply return with apparently no broken links found, which probably is not what you want to have happen!
      perllexwarn explains why use warnings is better than -w. use warnings FATAL => 'all' is even better than use warnings. And if you expect warnings to do parameter validation for you, you should be extra careful. It's usually easier to check them.
        This reference to perllexwar basically says that the problem can be that you turn warnings ON for more than maybe you want to.

        I figure that more aggressive warnings are usually better than less aggressive. If you get warnings that you decide are not warranted, then you can "crank down the warning level" for that segment of code, but usually (in my opinion) that's the wrong thing to do unless you are extremely clear about why you are going that.

        As far as parm validation goes, there is a whole bunch that didn't get talked about for this code example....use of prototypes in Perl functions, etc. In this case the issue was defined or not which is different than say param #3 should be between 4 and 12.

        In any event, I think that it is wrong to return silently when the sub fails.

        Update: In any event, I think that it is wrong to silently return a valid return value when the sub fails.

Re: Modifying Arrays passed by reference to subroutine
by Anonymous Monk on Jun 09, 2009 at 03:58 UTC
    Try my ($location,$broken_links) = @_; return unless (defined $location) ; return unless (defined $broken_links) ;
Re: Modifying Arrays passed by reference to subroutine
by sadarax (Sexton) on Jun 13, 2009 at 19:27 UTC
    Thanks for the help. Solved the issue with the information provided.