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

I'm writing a function that needs to take in an array and then splice it to insert an item into the array. Conceptually this should be very simple to do, however I'm having issues with the array and @_ or any other parameter array or variables.

This needs to produce "Hello World ! BANG!"

my @hello = ("Hello", "World", "BANG!"); sub ListInsert { my @lsList = @_; my $sItem = @_; my $nItem = @_; splice(@lsList, $nItem, 0, $sItem); print "@lsList\n"; } ListInsert(@hello, 2,"!");

But this prints "Hello World BANG! 2 ! 5" Any ideas?

Replies are listed 'Best First'.
Re: Passing arrays in subs
by kennethk (Abbot) on Jul 30, 2010 at 17:59 UTC
    Your variables do not contain what you think they do; after assignment:

    @lsList == ("Hello","World","BANG!","2","!") $sItem == 5 $nItem == 5

    @_ contains the entire argument list. This means you assign the entire argument list to @lsList and then repeat the assignment in scalar context, which assigns the length of the array (5) to your two scalars.

    If you want to pass an array into a subroutine, likely the easiest way to do it is with an array reference (see perlreftut). Your code might then look like:

    #!/usr/bin/perl use strict; use warnings; my @hello = ("Hello", "World", "BANG!"); sub ListInsert { my ($lsList_ref, $sItem, $nItem) = @_; my @lsList = @$lsList_ref; splice(@lsList, $nItem, 0, $sItem); print "@lsList\n"; } ListInsert(\@hello, "!", 2);

    Note I also reversed "!" and 2 in your argument list, since you had that backwards. Also note that I dereferenced the array before the splice to avoid affecting @hello. If you mean to change @hello, then you would need something more like:

    #!/usr/bin/perl use strict; use warnings; my @hello = ("Hello", "World", "BANG!"); sub ListInsert { my ($lsList_ref, $sItem, $nItem) = @_; splice(@$lsList_ref, $nItem, 0, $sItem); my @lsList = @$lsList_ref; print "@lsList\n"; } ListInsert(\@hello, "!", 2);
Re: Passing arrays in subs
by morgon (Priest) on Jul 30, 2010 at 17:57 UTC
    All the arguments to a sub-call are flattened into one list.

    So everyting you pass to ListInsert ends up in @lsList.

    You need to pass the first argument as a reference.

Re: Passing arrays in subs
by ahmad (Hermit) on Jul 30, 2010 at 18:18 UTC

    Well, I think you're doing just fine ... If you want to use a reference as suggested, then that's fine ... if you don't want to .. it's up to you.

    A simple fix to your code requires changing 2 lines only

    #Change my $sItem = @_; my $nItem = @_; # to my $sItem = pop @lsList; my $nItem = pop @lsList;
    Not Tested, but should work

      That doesn't really fix anything. The lexically scoped array will be altered, but the original array, @hello, won't end up with those changes in the main scope. speedyshady needs to use a reference, like morgon and kennethk have already said.

      Alternatively, your method could be used, but the new list would have to be returned.

        That doesn't really fix anything. The lexically scoped array will be altered, but the original array, @hello

        I've never seen the OP message saying "The original array should be changed"

        I've seen him creating a new array, but having difficultly to get the other variables values correct.

        So while others assumed he want to change the original array, I assumed he wants to create a new one ... what's wrong with that ... and what's all that -- for?

      I've decided that this is the easiest and best approach for the functionality of the larger picture. I don't want to call-by-reference, so brute-force seems to get the job done. After all, I'm really just rewriting the splice sub

      Also, thanks to everyone else, too because I actually learned a lot about assignments and passing of variables in Perl. Kinda tricky, but it makes sense.