in reply to Re: Re (tilly) 2: Use globals or pass around everything under the sun?
in thread Use globals or pass around everything under the sun?

In one sense, of course it is just as bad. It is a global. Same thing. Same problem. Sharing data across boundaries. As I point out in another post, passing by reference is also the same problem, same reasons, except that you have no opportunity to be explicit about what you are sharing, and have no opportunity for typo checks in your usage.

But there is a big benefit that you seem to have completely missed. The point of exporting functions etc is that it makes it much easier to rewrite code. You don't make any assumptions about where things are actually implemented, you just assume that they are available to you. And that means that if some functions in your package turn out to make more sense in another, you can go ahead and move them with very little editing.

You may think you are being careful by fully qualifying every function you use. I look at that and say that you are wasting a lot of typing to spread assumptions about where functions are implemented as widely in your code as you can. That is wasted typing for something that I consider a negative, not a benefit.

Now I am not saying to turn around and export everything. Export reasonably. Always through @EXPORT_OK so that people have to be explicit about where things came from. But exporting functions can be a good thing. Exporting variables, while not great, is often the best of bad choices. Being painfully explicit is just being painfully explicit. It may or may not be good, whether it is in any particular case is a judgement call.

  • Comment on Re (tilly) 4: Use globals or pass around everything under the sun?

Replies are listed 'Best First'.
Re: Re (tilly) 4: Use globals or pass around everything under the sun?
by lachoy (Parson) on Dec 04, 2001 at 20:29 UTC

    Trust me, I didn't miss it :-) I agree entirely that it's a judgement call whether to export/import functions, I just didn't make that judgement explicit in the previous post.

    So, to be explicit: I very, very rarely use non-class/object methods in my code. So the only areas where I find exporting/importing to be an issue are CPAN modules that export functions: File::Find, File::Path, etc. My reason for this is simple: many of these modules export very generic function names ('find', 'mkpath', etc.), and I find it more instructive to see:

    my $user_dir = File::Basename::dirname( $user_file );

    versus:

    my $user_dir = dirname( $user_file );

    If something goes wrong, the second one will have me looking around for sub dirname{}, the first one won't because it's a trusted source. (Then again, you could say that all libraries should be trusted sources -- to that I'd say, depending on the module, I'd trust others before myself :-)

    Again, this is two ways of doing the same thing. Instead of exporting a function I use a class or object. So instead of:

    use MyModule qw( myfunc ); my $result = myfunc( \%args );

    I'd do:

    use MyModule; my $result = MyModule->myfunc( \%args );

    What 'MyModule' does behind the scenes can be modified without the user ever knowing -- it could be transformed from a simple function to a factory method that creates an object behind the scenes based on \%args or the environment, whatever. And it opens up the possibility for a design where state needs to be maintained between invocations. It's easy to change this to:

    use MyModule; my $thingy = MyModule->new( \%args ) my $result1 = $thingy->myfunc( \%overriding_args1 ); my $result2 = $thingy->myfunc( \%overriding_args2 );

    So: TMTOWTDI :-)

    Chris
    M-x auto-bs-mode

      First of all you argument against exporting is only an argument against exporting functions in @EXPORT or through tags. If you only use @EXPORT_OK, then it is easy to find the imported subs - they are in your use line. Finding said function is very easy to do. Just look at the top of your code before you look for "sub foo".

      With the exception of a very few modules that come up so often as to be common knowledge (meaning I make an exception for param() but not much else), I never accept default export lists for exactly that reason.

      As for all of your comments about why classes and objects are good, you can do that within procedural code. I should know because I do. Plus a benefit of using procedural code over OO methods is that you are explicit about usage. It can be tricky to track down whether method foo() is in use, and if so, then where the version in this subclass might be called. And if you think you can get rid of it, but are wrong, you won't discover that until you actually exercise the call (by which point you may have forgotten all about that change.) By contrast with exporting functions it is clear which functions are public, and if you try not exporting something you think is unused, you will find that out very quickly when the other module refuses to compile with a message that indicates the broken assumption exactly.

      Of course OO has other things it does better than procedural code (I do write both), but for the simple task of controlled access to functionality from one place in another, my experience is that (at least in Perl) procedural is a significant win.