This sounds like a job for a few of my Perl OO 'best practices'.

First, use a hash ref not a list of pairs pretending to be a hash for the new API. It makes distinguishing between the old and new API clearer to both the module user and the module's code. It also leaves the most room for subsequent improvements to the API [ such as allowing ->create( {stackBytes=>32*1024}, subName, @args ) ]. Also, it makes the code generally clearer, including putting things like 'odd number of elements' warrnings where they make more sense.

Second, self-factories. Class-level configuration variables suck. But it is even easier (down-right trivial) to implement great "cascading configuration (defaults)" in Perl OO modules.

For module configuration parameters, the first thing you need is a good set of defaults. Then you need a place to store User A's default configuration choices that might be different from User B's defaults. Then you need to know what configuration to use for creating this next thread, merging the global defaults with the user's overrides to these defaults, with the options given in the call to create().

But, like I said, this is actually trivial to do and even gives the user the ability to have multiple layers of defaults and provides other API benefits.

Just store the parameters in a simple object, such as a hash. Then your global defaults simply become a class-global hash declaration. Users get their own identical object as a 'factory' where they can set whatever defaults they want and then create threads from the configured factory. Then they can make this factory as global or as limitted in scope as their heart desires.

And the object that gets associated with the new thread [the return value from ->create(...)] can be the exact same type of object, just with more data added in.

So it is as simple as:

my $default= { stackBytes => 4*1024, ..., }; sub getDefault { return $default; } sub new { my $us= shift @_; my $opts= shift @_; if( $opts && ! isa($opts,"HASH") ) { $opts= { code => $opts, args => \@_, }; } my $class= ref($us) || $us; my $proto= ref($us) ? $us : $class->getDefault(); my $self= bless { }, $class; my @configKeys= keys %{ $class->getDefault() }; # add error checking to taste here, # but this conveys the idea @$self{ @configKeys }= @$proto{ @configKeys }; @$self{ keys %$opts }= values %$opts; return $self; }

Then the user can say

my $threads= threads->new( { stackBytes => 16*1024, # default ... } ); ... my $worker= $threads->create( ... ); my $deep= $threads->create( { stackBytes => 32*1024 }, ..., ); $threads->setStackBytes( ... ); my @hive= map $threads->create( ... ), ...;

[ Note that new() and create() will be nearly identical and can be completely identical, depending on your API design tastes. ]

Now, if this were Perl 6, then the module user would probably get their first factory via something like:

my $threadFactory= use threads;

which has some nice advantages (like not requiring you to repeat the module name all over, the benefits of which are less obvious in the case of 'threads.pm', but mostly do still apply).

In Perl 5, the best you can do is a little bit more awkward. Now, the above example code means that people can go very traditional like:

require threads; ... my $child= threads->create( \&mySsub );

Or set up their personal defaults:

require threads; my $threads= threads->new( { stackBytes => ..., } );

But I like to make that easier, like:

use threads( Factory => \my $threads, StackBytes => ..., );

Which is pretty easy to do with a simple import() sub.

[ I notice that I've violated my own advice by not passing a hash ref to use threads and I'm unsure whether 'use' is enough of a special case that this departure is worthwhile... ]

- tye        


In reply to Re: New threads->create() syntax (best practices) by tye
in thread New threads->create() syntax by jdhedden

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.