in reply to Modular Code

Is there anything wrong with this snippet? Are there any easier ways to do it?
my @contents; &open_file(myfile.txt); sub open_file { open(FILE, "$_[0]") || die "could not open FILE $_[0]: $!"; @contents = <FILE>; close(FILE); }

Replies are listed 'Best First'.
Re: Re: Modular Code
by Sifmole (Chaplain) on Jun 14, 2001 at 22:41 UTC
    Well...

    open_file is not really just opening the file, it is grabbing the contents of the file; You might want to make the name of the sub match the action of the sub more closely.

    I would not declare the my @contents outside the sub and then rely on the side effect of the sub altering the data in contents. Instead I would pass the @contents into the sub by reference, and have it filled that way. This avoids creating two different arrays and copying them around via pass-by-value.
    Side effects can be confusing when code gets reused later. For instance this code snippet is only useful if you want to fill a previously existing array named contents -- not very modular.

    It also might be useful for the calling routine to be able to tell if an error occurred during the "grabbing"; Passing back an error code would allow the caller to gracefully recover from any possible error. I believe it is better to allow the caller to recover from the error rather than the "grabber" because any number of callers may want to react in a different way, so returning the code allows that -- reacting with the die inside the "grabber" does not. Returning a '0' can signify no error occured.

    my @contents; my $error = grabFile('myfile.txt', \@contents); sub grabFile { open(FILE, $_[0]) || return ($!); @{$_[1]} = <FILE>; close(FILE); return 0; }

    And this is not OOP.... OOP is much more than this.

      This is EXACTLY what I wanted to do. I didn't know you could do certain things like @{$_[1]} though. That will come in quite handy as I learn more about this. Got any suggestions where I could learn more about this type of coding?
        There is a small module called File::Slurp that you may want to look at.
Re: Re: Modular Code
by TGI (Parson) on Jun 14, 2001 at 22:49 UTC

    Put some quotes around 'myfile.txt' and the code will work as intended.

    I recommend using strict. It seems hard at first, but it is worth it in the long run.

    The biggest problem with slurping whole files into memory, is memory. If you know you will only be looking at a small number of small files it is OK. But what if someone throws a 250MB file into the mix? It is often better to process a file line by line.

    If you find yourself passing large arrays or hashes around, it is considerably faster and less memory intensive to pass a reference. Passing references will be faster and use less memory. Check out Dominus' Reference Tutorial

    For more on OOP, check out perlman:perltoot.


    TGI says moo

      Thanks TGI, I'm using strict. I just forgot to mention it. These are pretty much tiny files not over 20k. The biggest might be 100k. I'll check out that reference tutorial...

      Stamp_Guy

Re: Re: Modular Code
by runrig (Abbot) on Jun 14, 2001 at 22:26 UTC
    I would not set a global variable from a subroutine (This would be very un-OOP like, not that this is OOP anyway). And you don't need to quote the file when opening it:
    my @contents = &open_file(myfile.txt); sub open_file { open(FILE, $_[0]) or die "could not open FILE $_[0]: $!"; my @contents = <FILE>; close(FILE); @contents; }
Re: Re: Modular Code
by DrZaius (Monk) on Jun 14, 2001 at 22:30 UTC
    Yes!

    You are treating @contents as a global.

    I would do this like:

    use strict; use IO::File; my @contents = open_file('myfile.txt'); sub open_file { my $fh = IO::File->new($_[0], 'r') or die "Could not open file $_[0]:$!"; # slurp mode only if the don't want an array local $/ unless wantarray; return <$fh>; }