Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Passing variables

by Stamp_Guy (Monk)
on Jun 15, 2001 at 09:47 UTC ( [id://88713]=perlquestion: print w/replies, xml ) Need Help??

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

I have this subroutine which writes to a text file. It accepts two arguements: the file name and the array to print to the file. However, for some reason, it only prints the first item of the array. Any ideas what's happening?
sub writeFile { open(FILE, ">$_[0]") || return ($!); print FILE "$_[1]"; close(FILE); return 0; }
I call it like this:
&writeFile("file.txt", @file);

Any help would be greatly appreciated!

Stamp_Guy

Replies are listed 'Best First'.
Re: Passing variables
by lemming (Priest) on Jun 15, 2001 at 10:02 UTC
    Your subroutine is acting as programmed. You get a single array of arguments to work with in your subroutine.
    &writefile("file.txt", @array);
    arguments as writefile sees them:
    file.txt, 1rst array element, second array element, third array element, etc...
    So you are getting the file name as the first argument($_[0]), first array element as the second argument($_[1]), second array element as the third argument($_[2])

    What you could do to be clearer and in similar style:
    sub writefile { my ($filename, @array) = @_; open(FILE, ">$filename") || return ($!); print FILE @array; #nothing in between? close(FILE); return 0; }
    Though I would pass a reference to the array since that would be quicker. Hint: \@array and @$arref
Re: Passing variables
by frag (Hermit) on Jun 15, 2001 at 10:29 UTC
    The problem is that a list (ie @foo) inside another list (ie @_) gets expanded -- the list items are all there, but no longer enclosed in a distinct list. If @foo = (a, b, c), then your subroutine sees $_[1] as 'a', $_[2] as 'b', etc.

    To fix this, you could just print all of the remaining items in @_ inside writeFile, or else you could preserve @file's identity as a distinct list by passing it in as a reference:

    &writeFile("file.txt", \@file);
    Now, as far as writeFile is concerned, $_[1] contains a reference that points to all of @file, not just the first line. To use this correctly, you must also modify the print statement slightly:
    print FILE @$_[1];
    '@$_[1]' indicates that the program should access the array or '@' that '$_[1]' is a reference to. It can also be written as @{$_[1]}, if that helps.

    See perldoc perlreftut for a references tutorial, not to mention the various O'Reilly books.

    -- Frag.

      Thanks Frag. That makes sense. I appreciate the explanation. Thanks for spelling it out for me.

      Stamp_Guy

Re: Passing variables
by iakobski (Pilgrim) on Jun 15, 2001 at 15:05 UTC
    Well, I was going to write a bit about passing by reference and passing by value which the two replies so far have espoused, but when I did some benchmarks I was a bit surprised.

    First of all, for small arrays there is no noticable difference between passing by ref and passing by value. There is no surprise there. But it always amazes me how many experienced programmers insist on passing strings around by reference and so making their code far more difficult to read.

    Now suppose you have a large amount of data to pass to a sub, the question you might want to ask first is:

    Does Perl pass by array or by reference?

    And, as with most things Perl, the answer is Yes!

    When you pass something to a sub, it is passed by reference, but as soon as you assign that to a new variable a copy is created and so it looks as though it was passed by value.

    Now suppose you take a reference to @_ you have in effect passed by reference in a way that is transparent to the caller.

    Why would you want to do this? Well for the very good reason that you don't want to have to create references in the code that calls the subs. It is obvious that using references is more complicated than using straight variables, so if that can be hidden away in the sub it makes the code a lot clearer which is a good thing

    Now before I posted this, I wanted to test it. I started with this:

    sub write_array_1{ my $file = shift; my $r_array = \@_; open FILE, ">$file" or die "failed to open $file ($!)"; print FILE @$r_array; close FILE; }
    But the writing of the file was concealing the time taken for the array passing, so I just made sure every element of the array was accessed:
    use strict; use warnings; use Benchmark; sub write_array_1{ my $file = shift; my $r_array = \@_; $_++ foreach @$r_array; } sub write_array_2{ my $file = shift; my $r_array = shift; $_++ foreach @$r_array; } sub write_array_31{ my $file = shift; my @array = @_; $_++ foreach @array; } my @array = ( 1..100000 ); my $filename = 'C:\users\jake\testing\arrayref.dat'; timethese(30, { 'Pass by ref transparently' => sub {write_array_1( $filename . + 1, @array );}, 'Pass by ref explicitly' => sub {write_array_2( $filename . + 2, \@array );}, 'Pass by value' => sub {write_array_3( $filename . + 3, @array );}, }); Benchmark: timing 30 iterations of Pass by ref explicitly, Pass by ref + transparently, Pass by value... Pass by ref explicitly: 2 wallclock secs ( 1.84 usr + 0.00 sys = 1. +84 CPU) @ 16.27/s (n=30) Pass by ref transparently: 3 wallclock secs ( 2.94 usr + 0.00 sys = + 2.94 CPU) @ 10.21/s (n=30) Pass by value: 4 wallclock secs ( 4.42 usr + 0.02 sys = 4.44 CPU) @ + 6.76/s (n=30)
    So passing by value is slower (as expected) but why is the explicit passing by reference quicker than the transparent method? It's faster than passing by value so it must be doing what it's supposed to, but not the same as the explicit reference?

    -- iakobski

      My naive guess is that the overhead is in list expansion. I.e. in #1, you must go from qw(file.txt (1..100000)) to qw(file.txt 1..100000). This doesn't happen in #2 at all.

      -- Frag.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://88713]
Approved by root
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-20 06:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found