Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where do QuickCheck instances belong in a cabal package?

I have a cabal package that exports a type NBT which might be useful for other developers. I've gone through the trouble of defining an Arbitrary instance for my type, and it would be a shame to not offer it to other developers for testing their code that integrates my work.

However, I want to avoid situations where my instance might get in the way. Perhaps the other developer has a different idea for what the Arbitrary instance should be. Perhaps my package's dependency on a particular version of QuickCheck might interfere with or be unwanted in the dependencies of the client project.

My ideas, in no particular order, are:

  • Leave the Arbitrary instance next to the definition of the type, and let clients deal with shadowing the instance or overriding the QuickCheck version number.
  • Make the Arbitrary instance an orphan instance in a separate module within the same package, say Data.NBT.Arbitrary. The dependency on QuickCheck for the overall package remains.
  • Offer the Arbitrary instance in a totally separate package, so that it can be listed as a separate test dependency for client projects.
  • Conditionally include both the Arbitrary instance and the QuickCheck dependency in the main package, but only if a flag like -ftest is set.

I've seen combinations of all of these used in other libraries, but haven't found any consensus on which works best. I want to try and get it right before uploading to Hackage.

like image 978
acfoltzer Avatar asked Aug 12 '11 16:08

acfoltzer


1 Answers

On the basis of not much specific experience, but a general desire for robustness, the guiding principle for package dependencies should perhaps be

From each according to their ability; to each according to their need.

It's good to keep the dependencies of a package to the minimum needed for its essential functionality. That suggests option 3 or option 4 to me. Of course, it's a pain to chop the package up so much. If options are capable of expressing the conditionality involved, then option 4 sounds like a sensible approach, based on using language effectively to say what you mean.

It would be really good if a consensus emerged about which one switch we need to flick to get the testing kit as well as the basic functionality.

It's also clear that there's room for refinement here. It's amazing that Cabal works as well as it does, but it could allow for more sophisticated notions of "package", perhaps after the manner of the SML module system. Translating dependencies into function types, we basically get to write

simplePackage :: (Dependency1, .., Dependencyn) -> Deliverable

but one could imagine more elaborate combinations of products and functions, like

fancyPackage :: BasicDependency -> (BasicDeliverable, HelpfulExtras -> Gravy)

Until then, pick the option that most accurately reflects the actual deal. And tell us about it, so we can build that consensus.

like image 71
pigworker Avatar answered Oct 21 '22 06:10

pigworker