Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Weird array printing/passing to subroutine problem

by dmtelf (Beadle)
on Jul 10, 2000 at 15:55 UTC ( [id://21775]=perlquestion: print w/replies, xml ) Need Help??

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

Problem - code snippet below prints global array OK before subroutine is called. Array is passed to a subroutine and printed.

Only the 1st record gets printed inside the subroutine, but everything gets printed outside the subroutine. Why?

@AllFileDetails[0] = "blah, blah, blah"; @AllFileDetails[1] = "foo, bar, diddledum"; print "Printing array.\n"; print @AllFileDetails; print "\nCalling subroutine now\n"; &WriteToDisk(@AllFileDetails,files.txt); exit; sub WriteToDisk { @arraytowrite = shift; $writefile = shift; $text = shift; print "\nInside the subroutine 'WriteToDisk' now.\n"; print "Printing array.\n"; print @arraytowrite; exit; open (HANDLE,$writefile) || die "Cannot open open output file $wri +tefile for writing\n"; print HANDLE $ReportGenerated; print HANDLE @arraytowrite; close HANDLE; }

Replies are listed 'Best First'.
RE: Weird array printing/passing to subroutine problem (kudra: switch order of args, use strict)
by kudra (Vicar) on Jul 10, 2000 at 16:10 UTC
    Like ar0n said, if you want to pass an array, you should do it later, as all args are put in @_ together.

    Other notes:

    • This won't pass strict. Your variables in the subroutine should probably be 'my', and if you really want your arrays global, declare them as such. Read what davorg has to say on using these in example code.
    • You're only passing two arguments to your sub, but you're trying to get three out of @_, but it doesn't look as if the first arg of @AllFileDetails is really meant to be $text.
    • Put quotes around the string you're sending to the function if you want it preserved.

    Example:

    use strict; use vars qw(@AllFileDetails); # I'm using 5.005_03 $AllFileDetails[0] = "blah, blah, blah"; $AllFileDetails[1] = "foo, bar, diddledum"; print "Printing array.\n"; print @AllFileDetails; print "\nCalling subroutine now\n"; &WriteToDisk("files.txt", @AllFileDetails); exit; sub WriteToDisk { my ($writefile, @arraytowrite) = @_; # Thanks to davorg for pointing out that I was # only getting part of the array with my earlier # code! *blush* print "\nInside the subroutine 'WriteToDisk' now.\n"; print "writefile = $writefile\n"; print @arraytowrite; print "\n"; }
    The above was called with perl -w.
Re: Weird array printing/passing to subroutine problem
by c-era (Curate) on Jul 10, 2000 at 16:14 UTC
    You can also pass a referance to an array if you want to keep your params in the same order.
    @AllFileDetails[0] = "blah, blah, blah"; @AllFileDetails[1] = "foo, bar, diddledum"; print "Printing array.\n"; print @AllFileDetails; print "\nCalling subroutine now\n"; &WriteToDisk(\@AllFileDetails,"files.txt"); exit; sub WriteToDisk { ($arraytowrite,$writefile,$text) = @_; print "\nInside the subroutine 'WriteToDisk' now.\n"; print "Printing array.\n"; print @$arraytowrite; exit; open (HANDLE,$writefile) || die "Cannot open open output file + $writefile for writing\n"; print HANDLE $ReportGenerated; print HANDLE @$arraytowrite; close HANDLE; }
RE: Weird array printing/passing to subroutine problem
by mikfire (Deacon) on Jul 10, 2000 at 17:23 UTC
    Since we are here to refine our perl skills, I cannot add anything ot the answers already given, but I can ask why you are using positional parameters?

    It may be me ( my mind is like a steel trap... rusted open ) but I have an awful time remembering arbitrary order like this. I have found it much easier on myself to use named parameters instead. This also allows a much nicer syntax to give errors or default values.

    My take on your code would be

    @AllFileDetails[0] = "blah, blah, blah"; @AllFileDetails[1] = "foo, bar, diddledum"; print "Printing array.\n"; print @AllFileDetails; print "\nCalling subroutine now\n"; &WriteToDisk(details => \@AllFileDetails, filename => 'files.txt'); exit; sub WriteToDisk { my %params = @_; my @arraytowrite = @{$params{details}} || (); my $writefile = $params{filename} || ''; my $text = $params{text} || 'no text'; unless ( @arraytowrite && $writefile ) { print "Usage: WriteToDisk( filename => file to use, details => reference to an array holding the detai +ls "; return 0; } print "\nInside the subroutine 'WriteToDisk' now.\n"; print "Printing array.\n"; print @arraytowrite; exit; open HANDLE,$writefile or die "Cannot open open output file $write +file for writing:$!\n"; print HANDLE $ReportGenerated; print HANDLE @arraytowrite; close HANDLE; }
    This way, you never need to memorize the call order. Also notice the slight changes I made to the open HANDLE statement. You really want to use parens around both the open and the die arguements combined with ||, or you want to forget all the parens and use 'or'. Don't mix.

    Mik Firestone ( perlus bigotus maximus )

Re: Weird array printing/passing to subroutine problem
by davorg (Chancellor) on Jul 10, 2000 at 16:15 UTC

    There's a problem with your parameter passing. Within the subroutine, the parameters are recieved in the special array @_. This contains all of the parameters in one flattened list. In your case, this gives you:

    $_[0] = 'blah, blah, blah'; $_[1] = 'foo, bar, diddledum'; $_[2] = 'files'txt';

    When you then use shift to extract these values into local variables, it only pulls values off @_ one at a time, so you end up with

    @arraytowrite = ('blah, blah, blah'); $writefile = 'foo, bar, diddledum'; $text = 'files'txt';

    Which will probably explain the problem you see.

    What you should be doing is either passing a reference to the array or passing the array as the last parameter and pulling the scalars off the front first.

    --
    <http://www.dave.org.uk>

    European Perl Conference - Sept 22/24 2000, ICA, London
    <http://www.yapc.org/Europe/>
      Great point about the flattening of the passed array. That seems to hang a lot of new Perl programmers, myself included. Hangs them until they read perldoc perlsub.
RE: Weird array printing/passing to subroutine problem
by ar0n (Priest) on Jul 10, 2000 at 16:05 UTC
    When you do a shift on @arraytowrite,
    it only gets the first value in the array ($arraytowrite[0])
    see the docs on shift.

    What you want is:
    $writefile = shift; $text = shift; @arraytowrite = @_;

    You'll have to switch around you params, though.

    -- ar0n
RE: Weird array printing/passing to subroutine problem
by Ovid (Cardinal) on Jul 10, 2000 at 20:21 UTC
    Just a quick comment. I've seen this a couple of times in this thread:

    • You'll have to switch around you params (meaning that the filename to print to should be first)
    • If you want to pass an array, you should do it later (meaning that the array, or reference to such, should be passed AFTER the filename -- same as above).
    • You can also pass a referance to an array if you want to keep your params in the same order. (Passing an array reference is often a good idea, but not for this reason).

    So we have two posts telling dmtelf that (s)he has to have the filename first in the argument list (not true). We have one post stating that dmtelf can pass an array reference to keep the arguments in the same order -- this is not why an array reference is passed. The following would allow him to preserve his argument order:

    $writefile = pop; @arraytowrite = @_;
    Everyone is suggesting alternatives, but that seems so natural that I'm surprised it wasn't brought up. The only reason I mention this is that some shops have may have a standard that the filename comes last in an argument list or perhaps dmtelf was updating a function that is in a library that is required into many programs. If either of those were the case, we wouldn't necessarily have the luxury of changing the order of arguments.

    Also, though several people have corrected this, I don't see that it has been explicitly mentioned. @AllFileDetails[0] should be written as $AllFileDetails[0] with a '$' instead of an '@'. You're referencing a scalar here and Perl prefers that you use the scalar notation. What @AllFileDetails[0] actually does is take a one element array slice, which for all practical purposes is useless (and I suspect that it will have a negative impact on performance).

    dmtelf, if you are not used to passing a reference to an array, it is used to speed processing and save memory. What happens is that rather than passing the entire array to the subroutine, Perl (when passing a reference), just passes a value telling the sub where the array can be found. If you have an array with hundreds of elements, passing the reference is much faster. The main danger is that changing array elements in the passed array will now change the elements in the original array also. To actually get at the values in the array that was passed be reference, use the arrow '->' operator. Here's an example:

    #!/usr/bin/perl -w use strict; # Always use this!!! my @AllFileDetails; $AllFileDetails[0] = "blah, blah, blah"; $AllFileDetails[1] = "foo, bar, diddledum"; print "Printing array.\n"; print @AllFileDetails; print "\nCalling subroutine now\n"; &WriteToDisk(\@AllFileDetails, "garbage", "more garbage", "files.txt") +; print $AllFileDetails[1]; # This will print the new value exit; sub WriteToDisk { my $arraytowrite = $_[0]; my $writefile = pop; print "\nInside the subroutine 'WriteToDisk' now.\n"; print "Printing array.\n"; print $arraytowrite->[0] . " " . $arraytowrite->[1]; $arraytowrite->[1] = "New value\n"; # We've now changed the val +ue of $AllFileDetails[1]! print "\n" . $writefile . "\n"; }
    Cheers,
    Ovid
Re: Weird array printing/passing to subroutine problem
by ahunter (Monk) on Jul 10, 2000 at 21:37 UTC
    I'm surprised no-one has suggested it yet, but you can use prototyping to force things to happen the way you want:
    sub my_sub (\@$) { my $array = shift; my $scalar = shift; # $array is a reference to the array # $scalar is the next argument } my_sub @array, "scalar";
    Perl will automagically change @array into a reference for you. See perlsub for more information about prototyping.

    Andrew.

Re: Weird array printing/passing to subroutine problem
by jjhorner (Hermit) on Jul 10, 2000 at 16:45 UTC

    You are not using the 'strict' pragma. You therefore receive -- from me. This may just be a short snippet of code, but new people look at this and try to copy it. Don't shoot them in the foot.

    Most people complain about not knowing why someone votes down their posts. I'm explaining why.

    Moral: USE STRICT and USE WARNINGS!

    Update:

    kudra, again, points out something to which I'm oblivious. I do not mean to sound so brutal. I'm just trying to help you improve your perl code. Using 'strict' and 'warnings' will save you debugging hours and money, if you do this for a living.

    Take what I say in the spirit with which I say it: as a gentle rebuke to not-so-cool coding. I'm not personally attacking you. After all, you are a perl coder, that makes you better than the rest of the world. :)

    Special thanks to kudra. Between her and my new wife, I will be ready for public consumption in no time!

    Update #2:

    Once again, kudra proves to be wise beyond her years. here is a link to the post that started this trend.

    J. J. Horner
    Linux, Perl, Apache, Stronghold, Unix
    jhorner@knoxlug.org http://www.knoxlug.org/
    
      eduardo's thread explorations of consciousness and symbolic references...
      might give you new insight into the 'strict' controversy

      personally, i'd love to use strict but there are things
      that i can't do with it on (i've tried)

      i always try to use it for the first few lines of a
      proggie but wind up turning it off to get the job done

      i'd love to send my code to a perl clinic, so i could learn
      how to do those things (and i try that here from time to time ;)
      but i worry about treadding to close to the line on my NDA

      Update:

      after an email discussion with dave (i tried to include jjhorner but to no avail), i've
      got to admit that i was wrong. my being limited to non-strict code was a limitation of my
      own in how to use global variables

      eduardo's node did however make me feel better about not knowing how to do it tho' ;)

      thanks to dave fo going through a mighty heafty chunk of code, his responses are about
      to spawn another thread

        I'd love to see a few examples of code that refuses to be 'strict' compatible.

        Thanks.

        J. J. Horner
        Linux, Perl, Apache, Stronghold, Unix
        jhorner@knoxlug.org http://www.knoxlug.org/
        

        I'd also like to see examples of things that you can't do with use strict switched on. The only thing I can think of is symbolic references and there are better ways to do most of the things that they are used for.

        Even if you must do things that break use strict what's to stop you making most of the code strict-clean and putting no strict around the problem areas - together with a comment explaining what is going on.

        --
        <http://www.dave.org.uk>

        European Perl Conference - Sept 22/24 2000, ICA, London
        <http://www.yapc.org/Europe/>
      While I agree that your code should be able to pass both strict and warnings, I don't think that is always deserving of a -- vote. If the question being asked is directly caused by their failure to use these tools, and they are a professed newbie, then they need to be shown the light, not the door. On the other hand, if they are posting code in the snipits section, and it can't pass "-wc -Mstrict", then vote --. There is no reason to be unilateral about voting around here. If there was, then voting would be pointless.

      -Adam

      BTW, I trust that you only mean that the code should be able to compile with the "use strict;" pragma, not that the poster need include that line in their post, (unless it is a complete script).

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (3)
As of 2024-04-24 21:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found