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

I am new to perl objects, so please excuse me if this question seems a tad basic ;-)

I have a few rather large data structures that I want to use in a package (currently stuffed in a single file and required as needed).

Now I've decided that I really should try to get the hang of this OO stuff, and I'd like to know whether I can (or should!) use a require in the package I'm making (like in the scripts I've been using) rather than adding a few hundred lines to the package file itself, i mean like

package Blocker; use strict; use Switch; require "data_defs.pl"; ...

Would this create any problems? Would each object have it's own copy of the data, or would there still only be one like a require in a normal script? - Like I say, there is alot of data.

I would include some more code here, but you'd probably laugh at me (alot...!)

Thanks for any advice you can give!

Replies are listed 'Best First'.
Re: Require in modules...?
by ikegami (Patriarch) on May 10, 2009 at 00:55 UTC
    • Switch regularly creates hard (impossible) to debug problems. It's not meant for use. It's not even needed now that 5.10 has given/when.

    • do 'file.pl'; is more appropriate than require 'file.pl'; for files that don't have a package statement.

    • Unless data_defs.pl creates and populates an object with the data, it doesn't exist in any object.

Re: Require in modules...?
by Joost (Canon) on May 10, 2009 at 02:06 UTC
    require only loads a file if it hasn't been loaded yet, given reasonable checks, so it (normally) won't include stuff twice. and even if it *did* load the module twice, that probably doesn't mean you get multiple copies - that's all dependent on the scoping rules - "global" entities like named functions are unique and you cannot have more than one of them at the same time. Also, I consider it good form for a module to use/require all the code it depends on instead of relying on the user to do that.

    Anyway, that's to say that you can usually use require wherever you want.

    Now, it's probably better to use use instead, since use directives are processed earlier, and all you have to do to convert "data_defs.pl" to a useable module is to to rename it to "data_defs.pm" (that name is contrary to conventions but it'll work all the same).

    None of this has anything to do with OO - it's just a code loading mechanism - and also, you probably should not use Switch, since it can really mess up your code.

      Now, it's probably better to use use instead, since use directives are processed earlier, and all you have to do to convert "data_defs.pl" to a useable module is to to rename it to "data_defs.pm" (that name is contrary to conventions but it'll work all the same).

      I disagree. Modules can be required or used multiple times, but data_defs.pl cannot. To convert data_defs.pl to a module, you'll also need to add a package declaration, which means you'll also need to import the variables from the module use access them via their qualified names.

      If you want the loading to occur earlier, use

      BEGIN { do 'data_defs.pl' or die "Can't load data defs: " . ($@||$!); +}
Re: Require in modules...?
by pemungkah (Priest) on May 11, 2009 at 20:38 UTC
    I think we need to look at what data_defs.pl does.

    Do you want one copy of this data that should be consistent across all of your code (i.e., if package A asks for the data defs and fiddles with them, should only package A see those changes)? Or do you want a per-package copy? It looks like you want #2.

    I'd suggest creating a factory class that gives you the data you want when you need it. As a for-instance, let's assume we have some data that we want to get consistently right, but which we don't necessarily need to have all of in every module, and which shouldn't be shared with other callers. So something like this

    package DataDefs::Factory; use strict; use warnings; # define data here in 'my' variables ... my $hash_thing = { foo => 1, bar => 2, baz => 3, }; # and so on sub unshared_thing { # Called as a class method... my($class) = @_; # Make a copy of the data so that we'll not have # trouble elsewhere if the caller modifies it. my %copy = %{ $hash_thing }; return \%copy; } 1;
    Your module now does
    use DataDefs::Factory; my $thingy = DataDefs::Factory->first_thing;
    to get a "personal" copy of the data. If you wanted to have a singleton of a data item (that is, one copy that everyone shares), then you'd just return a direct reference to it instead of copying it to a second variable.

    If you have really complicated, deeper data structures, I'd recommend using Clone to make the copy that you return. Heck, you might as well just use Clone in the first place; that way if you change how complex the data structure is, you'll not have to alter the code.

    ... use Clone qw(clone); ... sub first_thing { my($class) = @_; return clone($hash_thing); }
    If your data's at all complex and you do similar operations over it in a number of places, you might want to consider making the package that you get the data from into a full-fledged class, and use accessors to get the data you want rather than rewriting the same code to crawl through multiple levels of data structure in multiple places.

    I could go into details about callbacks for iterating over depp structures and the like, but Mark-Jason Dominus has done it much better than I could in this space in "Higher-Order Perl". Check out http://hop.perl.plover.com// for lots on this topic.

      Sorry I haven't looked back for a while - I did see the first few comments, but now there are more. It's suprising what we can learn from each other!

      Anyway, I didn't make my initial question clear enough (my mistake, sorry): None of the data structures in data_defs will change (I hope!), and will be shared by all of the other modules.

      I would also like to make them 'global' - I tried using our for them but the only way I can make it work is to use this at the top of each file that needs them (although there are only a couple):

      require 'data_defs.pl'; use vars qw/ ... /
      where '...' are the structures in data_defs.pl.
      I have also tried making data_defs a USEable module, but I'm not sure which would be best for what I want.
      This namespace stuff is confusing the hell out of me!

      Anyway, thank you all very much for your help.
      Soooo much still to learn, but I love learning and love Perl even more. What a wonderful language!