Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Good practice for OO module defaults

by davies (Prior)
on Apr 08, 2019 at 09:35 UTC ( #1232282=perlquestion: print w/replies, xml ) Need Help??

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

I am writing a module using Moo. I want the object to have some defaults if values are not specified at creation. Some of the strings are quite long and it is conceivable that they may change. A config file is possible, but that would mean enforcing a directory structure on every machine, Windows or *u*x, which does not appeal to me. I therefore planned to use __DATA__ to hold the strings. There are plenty of warnings on this site not to use __DATA__ in production. Also, it causes problems. If I create two objects, the second comes without the defaults because __DATA__ has already been read. The options as I see them are:

  • 1. Go through the process of resetting __DATA__
  • 2. Memoise __DATA__ in some way.
  • 3. Use a config file.
  • 4. Hard code the strings at the start of the object.

I am minded to use the fourth of these, but would like to know the Monasteriat's recommendations.

Regards,

John Davies

Replies are listed 'Best First'.
Re: Good practice for OO module defaults
by GrandFather (Sage) on Apr 08, 2019 at 09:50 UTC

    Think about where someone who has never encountered the code before would most likely find and understand the default processing and defaults. To my mind having the strings in the construction code is a pretty reasonable way to do it. The code is clear, concise and easy to maintain without needing any additional explanation.

    If the strings are long and span multiple lines using HEREDOCs can make it easier to see how things hang together.

    For default handling defined or (//) is your friend.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: Good practice for OO module defaults
by Discipulus (Abbot) on Apr 08, 2019 at 09:50 UTC
    Hello davies,

    I'm not a OO expert (in what I'm expert? ;) but I almost always start with something like (perl 5.14 5.10 (see below GrandFather's answer) required to use //= ):

    sub new{ my $class = shift; my %conf = validate_conf( @_ ); return bless { %conf }, $class; } sub validate_conf{ my %conf = @_; $conf{ map_colors } //= 16; $conf{ map_area_w } //= 50; $conf{ map_area_h } //= 20; # more logic if needed.. return %conf; }

    So the fourth option for me

    HtH

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Actually defined or // has been around since 5.10.

      Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: Good practice for OO module defaults
by 1nickt (Abbot) on Apr 08, 2019 at 15:30 UTC

    Hi John Davies,

    A few points in random order:

    • It's recommended to always make an Moo attribute lazy unless there's a good reason for it not to be.
    • If your attribute is lazy you can declare a builder sub for it.
    • The builder sub can be anywhere, including a module that is basically just a config file (but lives in lib/).
    • The value of the default property of an attribute can also be a coderef or sub.
    • Most applications grow to need a config system at some point; I place changeable config data in config files as it's easiest to maintain. If you are concerned about directory structures you can make you config directory relative to the library directory.

    Hope this helps!


    The way forward always starts with a minimal test.

      "It's recommended to always make an Moo attribute lazy unless there's a good reason for it not to be."

      Recommended by whom? Plenty of attributes simply don't have any sensible default value. For many attributes, having them unset is itself meaningful. (For example, if you object has an output_file attribute, leaving it unset might indicate that you don't want it to produce any output.) And if the default is a simple value (like 0, 1, undef, or the empty string) then making it eager (i.e. not lazy) may have performance benefits.

        "... unless there's a good reason for them not to be."

        As for the recommendation, I can't find the original source but am sure I have read it in some doc somewhere. In my own experience it's usually the case that many if not most attributes depend on others or other things, and rather than try to remember all that I am lazy and use lazy and a builder. Of course that is not so in all cases, including e.g. your example of an attribute that has a static value.


        The way forward always starts with a minimal test.
Re: Good practice for OO module defaults
by QM (Parson) on Apr 10, 2019 at 10:13 UTC
    Option 2: Memoise __DATA__

    Can you have the package read __DATA__ and fill a package variable, if the package variable isn't defined yet? Something like:

    { my %config; sub new { if (not %config) { %config = read_config_from(__DATA__); } # Now create the object... } }

    I'm sure you could make this more flexible, reading from __DATA__ unless passed some other file or file handle.

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

    2019-04-11 Athanasius fixed opening code tags

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (3)
As of 2020-07-12 10:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?