in reply to Subroutines vs Modules

One useful way to think of a module is as a collection of related subroutines. They should be designed to be easy to use by any programmer without regards to the internals. Now think about a script which looks like this:

#!/usr/bin/perl use warnings; use strict; my @files = find_files(shift); foreach my $file (@files) { eval { process_file($file) }; die "Could not process $file: $@" if $@; } sub find_files { .... } sub process_file { .... }

With that, you have reused whatever code you have in &process_file. That's good. But what if another program needs the same functionality?

package My::FileProcessor; use strict; use warnings; use base 'Exporter'; our @EXPORT_OK = qw(find_files process_file); sub find_files { .... } sub process_file { .... } 1;

And your original code becomes this:

#!/usr/bin/perl use warnings; use strict; use My::FileProcessor qw(find_files process_file); my @files = find_files(shift); foreach my $file (@files) { eval { process_file($file) }; die "Could not process $file: $@" if $@; }

That code is now shorter, but more importantly, other programs can more easily share the functionality provided by My::FileProcessor.

Does that help?

Cheers,
Ovid

Ich verstehe nur ein bisschen Deutsch. -- Ovid.

New address of my CGI Course.

Replies are listed 'Best First'.
Re^2: Subroutines vs Modules
by sub_chick (Hermit) on Dec 30, 2005 at 03:34 UTC
    Ah, I see. If I am understanding this correctly, a module can be easily transported between programs of somewhat similar context and can be thought of as "universal" code. Whereas, subroutines are moreso used by the creator himself and is made for that program alone and not really thought to be exported to other programs. Am I getting warmer? :)


    Es gibt mehr im Leben als Bücher, weißt du. Aber nicht viel mehr. - (Die Smiths)"
      Slightly warmer, but you're still missing some pretty basic stuff.

      In Perl "subroutine" is just another name for a function. A function is a part of your program that you pass some arguments to, it does something, and it returns something. You might care about either the return or the action. For instance a logging function might write data to a file so you care what it does. Another function might perform a complex calculation, so you care what it returns.

      In Perl you declare a subroutine with the "sub" keyword, like this:

      # Declare it sub this_is_a_subroutine { # Your arguments are in @_. # Normally you'd do something more useful here. print "I'm doing something!\n"; return "This is a return value!\n"; } # Call it print this_is_a_subroutine(); # And here I'm going to terminate this program and # show you what output it would produce. __END__ I'm doing something! This is a return value!
      In this simple case the subroutine prints something and returns something else. Then the caller chose to print the other thing. So you see both values printed, with the returned value printed second.

      So you see, a subroutine has a very specific technical definition. Now a given subroutine might be very specific or general. It might be useful only in one program, or it might do something that lots of programs would like to take advantage of. Which will bring us to modules in a second.

      Subroutines are great. They allow you to structure your thoughts. In particular instead of writing 5-50 lines of code to do something you can write a function with a descriptive name, then call that function. A common problem in programming is that you can't see the forest for the trees - you see every detail about what is being done but have no idea what the point of any of it is. By organizing code into functions that have good names you manage to move things around so a high level view of what you're doing becomes more apparent.

      The alternative is that you cut and paste chunks of code. But now what happens if you correct a bug. Now you have to find everywhere that chunk got pasted and correct the bug in each place. Ugh. (In reality this doesn't happen and the same bug keeps on surfacing...)

      But for all of their strengths, subroutines could be better than what I've described. I've mentioned that some subroutines are useful in many different programs. But if you write them as part of the program, then you have to rewrite them for every program. That's where modules come in. Modules provide a place to put functions that can then be made available in many different programs without having to copy them to those programs. That's all a module is.

      Now nothing says that you have to organize your modules. You could just have a module called "my_functions", stick a ton of functions in there, and load it from everywhere. This works, but is a bad idea for the same reason that it is a bad idea for libraries to randomly put books on shelves wherever they happen to fit first.

      Instead it makes more sense when you put related functions together into a module so that there is some conceptual coherency. Now you know that all of your date manipulation routines are in Date::Time, your web download code is available from LWP::Simple, and your probability distributions are calculated by Statistics::Distributions. And more importantly if you're looking for a specific function, you know where to look so that you can find it, remember what the bloody thing was called, and figure out what you need to pass it!

      So in summary, a function is a piece of code that you can easily call from within your program. A module is a way to make a collection of functions available in many programs without having to rewrite the functions within each program. And it is a very good idea to give your functions names saying what they do, make them do that, and organize them into modules. (A great deal of becoming a good programmer is becoming good at organizing functions and modules.)

      ...a module can be easily transported between programs of somewhat similar context and can be thought of as "universal" code. Whereas, subroutines are moreso used by the creator himself and is made for that program alone and not really thought to be exported to other programs.

      you are looking at the consequences of modules vs. subroutines, and your observations are correct, but only because there are technical reasons that make them so

      Fundamentally speaking, a subroutine and the subroutines IN a module are identical (note that your "subroutine to module" comparison is not quite apples to apples)*, they differ by being subroutines that exist in different namespaces (aka., in perl, packages)

      it's because you can segregate your subroutines by namespace in this way that makes it easy to move the code between programs (and programmers) - it also helps that modules typically exist in separate files too (of course).

      *footnote: it's an easy mixup to make, because most modules present themselves as offering a single object, sometimes a single subroutine even

        (note that your "subroutine to module" comparison is not quite apples to apples)*
        subroutine is to module as apples are to labeled basket of apples