http://qs321.pair.com?node_id=273110

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

First off, I am not sure of the title so anyone who has a better title feel free to edit it.

I am creating a wxPerl application and there are several utility functions that I need in almost every other module used by the application.

What I have ended up doing is exporting these utility functions into the main namespace, which allows me to write (for example)

my $id = &::get_id();
in any module that needs it (which as I said is pretty much every module). This way I can avoid having to explicitely import the util functions in each and every module.

This works, but my question to my fellow monks is would any of you find this confusing to maintain? Or would you consider it a bad idea in general?

Thanks for any input/criticism/tomatoes that you can lob my way.

  • Comment on Exporting functions into main namespace for the benefit of other use'd modules
  • Download Code

Replies are listed 'Best First'.
Re: Exporting functions into main namespace for the benefit of other use'd modules
by tedrek (Pilgrim) on Jul 10, 2003 at 20:02 UTC

    My first reaction is that this is a bad idea, it means that your modules are relying on certain functions to exist in the 'main' namespace. It would seem to me to be clearer to simply have a use Foo::Utility qw/:common/; at the top of each of these modules, that means your modules are only relying on things they have control over. That also has the benefit of meaning you can now say

    my $id = get_id();

    That alone will probably save you typing, which seems to be what you were worried about in the first place. If you were worried about actually loading the module multiple times, don't, perl only loads it once.

    Exporter will give you everything you need to do in Foo::Utility with very little effort (if you weren't already aware of it).

Re: Exporting functions into main namespace for the benefit of other use'd modules
by halley (Prior) on Jul 10, 2003 at 20:04 UTC
    There's a namespace called main and there's a namespace called CORE. All the builtins are in CORE, while anything in the initial script are in main. When you give &::foo, it's really seen as &main::foo.

    If you really wanted to make something available to everything, you'd alias it into the CORE namespace. Some modules like the File::Glob actually do this if you ask for it explicitly, but it's quite dangerous to do this willy-nilly.

    In general, you should export symbols to your caller, not to the world. You might not know how large or diverse your runtime world really is, and other modules in this runtime world may not be expecting your changes. If they like your exports, they can use your module to get them.

    --
    [ e d @ h a l l e y . c c ]

Re: Exporting functions into main namespace for the benefit of other use'd modules
by Zaxo (Archbishop) on Jul 10, 2003 at 20:05 UTC

    IMO, each module should either import or fully qualify what it needs from the specific package where it occurs. I think that what you suggest would be infuriating to maintain and the cause of frequent errors.

    Keep main:: as clear as you can.

    After Compline,
    Zaxo

Re: Exporting functions into main namespace for the benefit of other use'd modules
by BrowserUk (Patriarch) on Jul 10, 2003 at 21:36 UTC

    If you are really going to 'globally expose'(1) utility functions this way, then you should at least give some thought to the names, and get_id() is just about as bad as it gets.

    (1) Which seems to be your intention, though as halley pointed out the definition of global is somewhat limited.

    What id is that? A file identifer? A personnel identifier? A user identifier? A group identifier? A rabbit identifier? Is Idaho up for sale? Your program is a step in your quest for world-domination and your starting with Indonesia?

    Or maybe the problem you are solving needs a little Freudian help, and some impulsive behaviour?

    And is that get a new one? The old one? The only one? The current one? The next one?

    Once you have addressed those questions, your likely to end up with a sub called retreive_current_effective_user_id_for_this_process();, but then that would probably be more easlily written as Process::Current::user_id(); (season with get/put, or get/set to taste).


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


      sigh

      First off, thanks for the levity. But it also, as I assume you intended, points out a very valid problem.

      My only response is to say that the name makes perfect sense in context. But I obviously did not supply the proper context, and perhaps it would not make perfect sense to someone else.

      The id refers to a unique id that is required by each wxPerl object that is part of the application (eg textboxes, buttons, frames, etc.).

      This whole thread has got me thinking on the question of whether I can assume a minimum level of knowledge about the overall application or if each module that makes up the application has to stand on its own.

      Thanks for the response.

        i think you may be better served by OO, using functions as objects.
Re: Exporting functions into main namespace for the benefit of other use'd modules
by tunaboy (Curate) on Jul 10, 2003 at 21:09 UTC

    Judging from the responses so far, the consensus is this is a bad idea but I think I did not give enough background on what I am doing. The modules that are using these functions are not 'standalone' modules, they are part of the whole that is the application.

    The application starts with a .pl script consisting of:
    use strict; use warnings; use Foo; my $app = Foo::App->new(); $app->MainLoop();
    That is all there is in the main namespace. The Foo package is responsible for loading Foo::App which in turn loads other modules necessary (which in turn load other modules necessary etc. etc.). Foo is also the package that exports the utility functions into the main namespace.

    None of the modules that require the utility functions will ever be used outside of the application as they are all specific to the application. As an example, each different window in the application is a seperate module (at around 50+ right now).

    The modules are meaningless without looking at the application as a whole, which is why I felt it ok to shortcut the importing of these functions. I can guarantee that the functions will be in the main namespace and they will not be messing with any other functions there (as there are none). But the problem comes when someone else comes along to maintain/extend the application. Perhaps I am being too 'clever' for my own good.

    I think I may reconsider as it does only mean one extra line in each module and it will eliminate a possible source of confusion for a maintainer.

    Thanks for the posts.

      use strict; use warnings; use Foo; my $app = Foo::App->new(); $app->MainLoop();
      Looking at that, I'm already wondering
      • Why "use Foo" and not "use Foo::App"?
      • Why would there be anything else in main?
      I'm still not seeing anything in your proposed design that offers anything that's not implementable in a proper design as suggested by others in this thread.

      Maybe what you really have is an example of a specific derived class that inherits these common functions from a base class.

      Or maybe something else entirely.

      But I'd be very confused if I had "package My::Package" and then found that there were other subroutines that poofed into my namespace when I hadn't specifically imported them. Argh!

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

Re: Exporting functions into main namespace for the benefit of other use'd modules
by SmokeyB (Scribe) on Jul 11, 2003 at 18:39 UTC
    Personally, this is what I would do when creating and importing my module. Creating module:
    package YourModule; require Exporter; use strict; use vars qw(@ISA @EXPORT @EXPORT_OK); @ISA = qw(Exporter); @EXPORT = qw(get_id AnotherSub); @EXPORT_OK = qw(evenMoreSubs justOneMore);
    Under @EXPORT place all of the subroutines that will use in all your other modules, and then call it like so:
    use YourModule qw (:DEFAULT); use strict; my $id = get_id();
    If you include the :DEFAULT tag, it will use all subroutines from @EXPORT. This should do what you're looking for. Cheers!