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

There are some functions that I am constantly doing. One of these is opening files. I would like to be able to have a subroutine or something that I could just pass a few values to and have it return the contents in an array. Is this what OOP is about? Pardon my ignorance. I would appreciate your thoughts on this subject. I'm not sure if I'm being clear enough, so if I'm not, please let me know. Thanks.

Tim

Replies are listed 'Best First'.
Re: Modular Code
by tinman (Curate) on Jun 14, 2001 at 22:37 UTC

    In short: no, not exactly.. :o) I'll try to explain my grasp of the concepts as best as I can..

    First of all, OOP is not *only* about reuse. Reuse is a good side effect of using objects, but there are other good effects too..

    If you're doing a particular job over and over again, the first place I'd look is to move that code into a sub (subroutine)... Saves overhead, avoids duplicating code all over the place..

    OOP deals more with concepts of modularization and abstraction.. Firstly, take the following example:
    You have a function which maintains a bank balance. If all you need to do is subtract and/or add amounts from the bank balance, two simple functions named "add_to_account" and "subtract_from_account" would be fine... Pass in the balance, and the amount to add or subtract, and you get a result...However, suppose you also want to maintain the state of the bank balance inside the function ? if you don't want to maintain the balance in your application, then an OOP system is good...

    Objects can help you maintain state... to follow the same example:

    The procedural method: $balance = add_to_acct($balance, $amount); The OOP method: my $acct_obj = new BankAccount($initial_balance); $acct_obj->add_to_acct($amount);

    In other words, what's happened here is that the explicit maintenance of a bank balance has been abstracted away from you.. The object maintains the state of the bank balance... Think of an object as a neat little package which contains all the variables and function calls you need to do a particular job..

    As I understand your problem, if you just need to open a file frequently, then an OOP interface is probably overkill.. for your second question, if you want something like this:

    add_value($x); add_value($y); add_value($z); my @all_values = get_all_values;
    then an object oriented interface looks nicer, but isn't really necessary... you could write it procedurally as:
    @all_values = add_value($x, @all_values); # gives the list to add to, and takes the newly added list # as a retu +rn value @all_values = add_value($y, @all_values); ... # Now anytime you inspect @all_values, it has the currently # added el +ements.

    Most of this is probably oversimplified.. a look at perltoot,perlsub or searching for object oriented tutorials will probably explain things better...

    HTH

Re: Modular Code
by nysus (Parson) on Jun 14, 2001 at 22:28 UTC
    You could do that with OO but it would be overkill. A simple subroutine in a module would suffice. See perlsub to learn more about subroutines. Like run-of-the-mill subroutines, OO allows you to create large building blocks out of very small ones. Unlike regular subroutines, they are much more efficient (code wise not speed wise) making the creation of very large, complicated programs possible by making it easier to maintain the code (if you know what you are doiong, of course). I'll leave it to a real OO guru to fill in the details on the advantages of OO over subroutines.

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot";
    $nysus = $PM . $MCF;

Re: Modular Code
by Stamp_Guy (Monk) on Jun 14, 2001 at 22:18 UTC
    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); }
      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?

      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

      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; }
      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>; }
Re: Modular Code
by dimmesdale (Friar) on Jun 14, 2001 at 22:27 UTC
    Well, this simple example isn't really the heart of OOP. (Rather than get off on a rant, just search this site and others, as there is a wealth of OO info.) If all you want is a way to get the contents of a file in an array, and open it in one line, just make a function. It seems that what you want to do is make a module to group a lot of miscellaneous things together to make it easier. . . and this would be a good course to go, but I think it would be easier if you just made it a module, rather than an object-oriented approach. i.e., an OOP places the importance on data (and its abstraction), however, you seem to just want a quick way to do various, unrelated(and unrelated data, as a result) tasks. . . My advice, stick it in a module, but steer clear of OOP.

    Book reccommendation: for a good OO book, check out Data Abstraction with C++ (not exact title). It was required in my C/C++ class, and it was pretty good--it showed examples with C++, but the principles can be applied around the board. Though, if you are interested in OOP w/ perl, checkout the objperl manpage and look for literature/links directly related to perl.