@Bodigrim commented here saying:
Imagine re-exporting
HUnitFailure
fromHUnit
intasty-hunit-0.11.0.0
withbuild-depends: HUnit >= 1.6 && < 1.7
. IfHUnit-1.6.3.0
adds any instance forHUnitFailure
, it will leak fromtasty-hunit-0.11.0.0
as well. This means thattasty-hunit-0.11.0.0
fails to provide a stable interface and clients withbuild-depends: tasty-hunit == 0.11.0.0
have no control of it.
IMO this is just an example for why you should pin transitive dependencies (e.g. with a snapshot or with a freeze file). Any other language ecosystem (I’m familiar with npm + pypi) is perfectly fine with packages reexporting from other packages, and it’s commonly understood that you should pin transitive deps to get truly reproducible builds.
I get that Haskell instances are a little more magical (global + automatically reexported), but I don’t see why it’s any different than reexporting a constructor and the upstream package changing fields. Maybe it’s because docs will get outdated? I’m curious if Rust has similar issues then.