Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Coding Perl With Style

by Dogma (Pilgrim)
on Nov 27, 2001 at 06:01 UTC ( [id://127696]=perlquestion: print w/replies, xml ) Need Help??

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

This is more a question of what is considered good style then functional programming. I have a perl module/class that is dependant on about a dozen 'global' variables being imported from a "config.pm". All other modules in this application use this same "config.pm" to get at these 'global' variables as well. Is this considered acceptable style or should all code (especially classes) be totaly decoupled? I don't suppose it would be any great hardship to pass a ref of a hash that includes all these variables to every single function call in this application but that doesn't seem to tidy to me. An thoughts/criticism one way or the other?

On a related topic... If I declare a scalar as a constant in a module then export that scalar will it remain a constant? I'm not so much worried about it remaining constant as I am get compile time replacement in any script/module that has that scalar exported into it. Does that make sense to anyone else?

Replies are listed 'Best First'.
Re: Coding Perl With Style
by wog (Curate) on Nov 27, 2001 at 06:31 UTC

    "config.pm" is not a good name for a module. "Config.pm" is a built-in module to perl. Names beggining with lowercase letters should be considered reserved for pragmas; they are considered "special". "Something::Config" would probably be okay, however.

    As for your actual question, you could probably make an object that encapsulated this configuration stuff , or (updated) and have your exsiting classes have it as an instance "variable". Or you could, as you suggested, just pass it as an argument to every function. I see no problem with either of these approaches; it is far cleaner then having your code not be so reuseable and modular.

    If I declare a scalar as a constant in a module then export that scalar will it remain a constant?

    "constants", as you are referring to, are actually functions that have a prototype of () (explictly no arguments), and thus are inlined by perl. You will get this optimization as long as the function is imported (so perl what to use and that it should inline it) when the relevant code is compiled.

      Actualy config.pm isn't the real name. It's Yaps::Config.pm so we're on the same page there. So your suggesting using Config.pm as a base class and having all classes inherit from it. Like a smalltalk-90 oo tree right? Thanks for the answer about inlining.
        I would personally think you want a "has-a" relationship. "Configuration" info is shared by many (instances of) classes; it is not something that each of the instances should maintain an independent copy of.

        (update: Nor do I think you should have one copy of it be held statically by a base class, of course. I would prefer to leave room to maintaining to independent sets of this data in one application, if need-be.)

(jeffa) Re: Coding Perl With Style
by jeffa (Bishop) on Nov 27, 2001 at 06:32 UTC
    Sounds like you need to look into OOP - check out perltoot and look in Tutorials here.

    Now, is OOP going to solve all of your problems? No. Check out Big Ball of Mud. OOP is just the tool, the results depend upon the coder wielding it.

    Second question - yes, it will remain a 'constant' and you will get a run time error if you try and change it. And i didn't know why until wog said it. ;)

    To elaborate more, this is a way i would do it:

    package Foo; use constant BAR => 27; sub bar { return BAR }; 1;
    Providing accessor methods tends to keep folks from trying to change the guts, but not always.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    F--F--F--F--F--F--F--F--
    (the triplet paradiddle)
    

      When I write a 'getter' of a static value, not used by other methods in the same module, I tend to write:

      package Foo; sub bar {27;} 1;


      If more than one method in my module needs this value, then I let the other methods all use the first method, the one having the value hard coded (in this case 'bar').

      Any pros and cons to this approach?

      f--k the world!!!!
      /dev/world has reached maximal mount count, check forced.

Re (tilly) 1: Coding Perl With Style
by tilly (Archbishop) on Nov 27, 2001 at 06:55 UTC
    One stylistic question I would suggest thinking about is why the lines of your logic as drawn by variable usage is not matching the lines of your logic as drawn by your modules.

    I do not mean to imply by this that they must match. Often you will have a variable (eg a debugging flag) which naturally cuts across module boudaries. However it is often true that when you want to use a variable in many places, it would be cleaner to encapsulate the logic that said variable is used to control into some functions that you isolate into a module. (For instance for the debugging flag you could have a logging function.)

    Something to be aware of and think about.

    BTW in answer to your specific question, my personal answer is to use an application configuration module where each module says what variables it will import from its configuration scripts, but the configuration scripts are themselves kept in the same directory. Variables that need to be shared across multiple modules can be imported by the configuration scripts and then re-exported. A bit complex, but it works quite well for a system with ~60K lines of Perl.

      BTW in answer to your specific question, my personal answer is to use an application configuration module where each module says what variables it will import from its configuration scripts, but the configuration scripts are themselves kept in the same directory. Variables that need to be shared across multiple modules can be imported by the configuration scripts and then re-exported. A bit complex, but it works quite well for a system with ~60K lines of Perl.

      This is essentaly what I'm doing. The Yaps::Config.pm reads in configuration data, creates several hashes, hash a couple of larges hashes itself, sets several flags (including debug flags), and global configuration data and exports it. All other parts of the application use this module to get at that data.

Re: Coding Perl With Style
by clintp (Curate) on Nov 27, 2001 at 19:15 UTC
    Anecdotal testimony: this is only a passive endorsement.

    Most of the projects I've been on, including the current one what we've done for variables that really need to be accessed from everywhere is first invent a unique namespace for the client. For example, "JacksLumber" Then we create a JacksLumber.pm and in there put all of the global variables we're gonna need as package variables (excused from strict with use vars).

    The modules then go under the JacksLumber directory with names like JacksLumber/Tags.pm, JacksLumber/Security.pm, JacksLumber/LnF.pm, etc...

    Within the main script "global" values are always accessed by the full package name. For example, $JacksLumber::basedir or $JacksLumber::appname. This has a few effects. First, it doesn't pollute the namespace of the script (like an import might do). Secondly, it makes "global" things stand out (yeah they're lengthy, but you shouldn't be typing them often anyway). Thirdly, we don't have to introduce unnecessary OO complications or encapsulation overkill for things that might not need it. (Although we do have a lot of OO and encap. in other places where it is needed.)

      I personally like this approach. It also lets application developers using your module do something like this:

      use JacksLumber; $JacksLumber::basedir = '/some/other/dir'; # override default

      This is simple and intuitive and avoids having the user of your module learn your configuration interface if he wants to make changes to these simple variables.

      HOWEVER, what if your configuration is complex? What if it's structured? What if you can't predict what the variable names will be while you're coding? You don't want to pollute your module's namespace with an unknown list of variables, so you gotta go with a hash (and perhaps a complex data structure).

      I've used a few different approaches, depending on the project. I've exported a %CONFIG hash (or a hashref), I've created an AUTOLOAD in a ::Config module that let me reference configuration as JacksLumber::Config->key and other things. I still haven't come across a technique that I liked that was well-suited to any project, and invariably I start with a simple approach that ends up more complicated, making my configuration approach too constraining. For example, if 'dir' was a variable under a 'base' hierarchy, I'd end up with something unmaintainable like JacksLumber::Config->base->{dir}. How intuitive is that? With the use of things like Class::Struct and similar modules, you might be able to make that a little more readable, but it's still ugly in my eyes.

      If your "global" variables might change between invocations of your package methods/functions, you might consider wrapping your configuration in an object, and set up object methods (or a generic 'get'/'set' pair) to allow you to set/fetch your "global" variables. In other words:

      # Go from this: use JacksLumber 'some_func'; $one = some_func(1, 2, 3); $JacksLumber::alternate_behavior = 1; $two = some_func(1, 2, 3); # To this: use JacksLumber; my $normal = new JacksLumber; my $alt = new JacksLumber(alternate_behavior => 1); $normal->some_func(1, 2, 3); $alt->some_func(1, 2, 3);

      But generally, the simplest thing to do might just be a hash or a hashref in your module's root namespace for complex configuration, or just some package variables if you can get by with that.

      Just my two cents...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://127696]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2024-03-29 04:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found