I'd usually pick the separate package option — but then I don't use stack test --coverage
. Thanks for introducing me to it!
(Edit: I'd probably do this, and then use the test flag option only for running stack test --coverage --flag thepackage:arbitrary
so that nobody else has to deal with the flags.)
It may also be worth raising the --coverage
issue on the stack
issue tracker, as it would be good for the coverage check to work in this case.
You ask for other options — the best one is probably a test flag.
A test flag
It is possible to define a flag in your cabal file (defaulting to false) which will only build the modules with your QuickCheck dependency if the flag is selected.
Place the required code in the directory arbitrary
(for example). Then add the equivalent of the following to the relevant parts of your package.yaml
(1st snippet) or the-library.cabal
(2nd snippet) file:
flags:
arbitrary:
description: Compile with arbitrary instances
default: false
manual: true
library:
⁝
when:
- condition: flag(arbitrary)
dependencies:
- QuickCheck
source-dirs:
- arbitrary
flag arbitrary
description: Compile with arbitrary instances
manual: True
default: False
library
⁝
if flag(arbitrary)
hs-source-dirs:
arbitrary
build-depends:
QuickCheck
Then, packages which want to use the instances should add the following in their stack.yaml
(1st) or cabal.project
(2nd) files:
flag:
the-library:
arbitrary: true
constraints: the-library +arbitrary
But there's a slight problem… there is currently no way for that library to only depend on the +arbitrary
version in only its test suite, unless it also defines such a flag. This may be a price worth paying.
Note: I haven't tested the downstream packaging, yet.
Ivan Milenovic's blog was useful as an initial resource.
DerivingVia/Generic instances
There may be another possibility, now that GHC 8.6 has been released, with DerivingVia
. There's a case study in Blöndal, Löh & Scott (2018) for Arbitrary
instances.
You would create newtype wrappers, and implement Arbitrary
for those newtypes.
It doesn't quite avoid the problem, as is. But you may be able to implement Generic
for those newtypes in such a way that the instances derivable using generic-arbitrary
match what you'd want.
There may be some other options. In particular, QuickCheck
's dependencies aren't actually that heavy. And there are other testing libraries, too. Plus, note that there has been some discussion of separating an Arbitrary
-like typeclass into a standalone library.
I would also have suggested internal libraries, but that doesn't allow other packages to use your instances.