However, in Perl we have CPAN from which we install our modules...this allows us to specify dependencies be be installed when we install our module. In this Perl Advent Calendar example, why would we create a ReindeerFactory instead of just forcing our module to install Robo-Reindeer if that's the one we prefer?

IMHO, you're right to question this. Factory classes are often used in strongly typed languages like Java, I myself have for example written a Logger interface with different underlying implementations. The important thing to note is that the user of my library specifically chooses which implementation they want, and the factory class is helpful because the language is compiled and strongly typed; it's not as simple as Perl's "a constructor can return whatever it wants".

However, the conditional loading of modules depending on something outside of the user's control is something that I nowadays think should be very sparingly used for exactly the reason you hint at: if I've written my code to depend on a certain module or functionality (RoboReindeer), then trying to adapt my code to environments where that module isn't available (BioReindeer-only) is often more work than either backporting RoboReindeer to that environment, or simply declaring that my code requires RoboReindeer, with whatever limitations that brings.

For me, it comes down to the question of well-defined behavior. If I'm writing a library, I don't like telling the user of my code "you ask for a reindeer and maybe I'll give you a BioReindeer or maybe a RoboReindeer, why do you care?" because more often than not there is a difference between the two that will have my user jumping through hoops to cope with that difference down the line (if ( $reindeer->isa("RoboReindeer") ) { do_this() } elsif ( $reindeer->isa("BioReindeer") ) { do_that() } else { die "unknown species" }).

On the practical side, let's say I write a library that uses *Reindeer, and when the user installs my library they only have BioReindeer installed, so only that subset of my module's test suite gets run. If they install RoboReindeer later, my test suite may never get executed against the RoboReindeer they installed, which again may lead to problems.

So for these reasons nowadays I lean very strongly towards simply saying "the users of my library are getting RoboReindeers, period".

There are of course exceptions, an important one is the OS-dependent implementation of a platform-independent interface, as choroba indicated - one of the big ones in the Perl core is File::Spec, for example. Another one is the automatic loading of XS-based versions of otherwise pure-Perl modules when they are available (as long as the two really behave identically and the XS version is just an optimization). And a last reason that I can think of at the moment may be if you're trying to gradually transition your code away from one dependency onto the other.

(It's late and I don't have the time to investigate further right now, but I'd be genuinely curious if there are other useful uses for the "recommends" and "suggests" relationships of CPAN::Meta::Spec.)

Update: Thinking about this a bit more, I guess what I am saying is that my experience simply doesn't line up with the premise of the article, in particular the first word:

Often we find ourselves writing code that copes with optional dependencies; Code that will use a module to do amazing things if it's installed, but will muddle through with some lesser code path if that dependency is missing or unavailable on the system.

Instead, I think that most of the time one thinks one is in this situation, there is a different and often more pragmatic solution possible.


In reply to Re: Factory classes in Perl (updated) by haukex
in thread Factory classes in Perl by Bod

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, 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, 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.