Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Packages sometimes (?) want to declare constraints on indirect dependencies #9558

Open
michaelpj opened this issue Dec 23, 2023 · 2 comments

Comments

@michaelpj
Copy link
Collaborator

In recent discussion I made the claim that there are situations where a package may want to state constraints on indirect dependencies. Here are a couple of examples where that applies:

  1. The indirect dependency has a bug

Suppose we have:

  • my-pkg, which depends on
  • foo-processor, which depends on
  • foo-parser

but my-pkg does not depend on foo-parser directly.

Now suppose that foo-parser-1 has a bug such that it doesn't process certain kinds of .foo files properly. Then the tests for my-pkg might be failing if I have such files around. Suppose the bug is fixed in foo-parser-1.0.0.1 (a patch release since it's just a bug fix behavioural change).

Then it is the case that my-pkg won't work unless it is built with foo-parser-1.0.0.1 in the build plan, but we have no way to state that without either a) adding a spurious dependency on foo-parser, or b) getting a pointless release of foo-processor which adds a lower bound of foo-parser-1.0.0.1.

(Why would we care? Isn't foo-1.0.0.1 newer, so cabal will pick it? Usually yes, but various things can get in the way (index-state set too old, other constraints preventing it from being picked), and we would e.g. like to get a solver error in that case rather than wrong behaviour.)

  1. Some combinations of versions may not work together

turtle depends on optparse-applicative and ansi-wl-pprint. For various complicated reasons, most combinations of these libraries work together, but the specific combination of a new optparse-applicative and an old ansi-wl-pprint would not and would lead to build errors.

From the point of view of the turtle maintainers, the situation seems fine, but for a package which might force an old ansi-wl-pprint, it would be useful to also be able to force an old optparse-applicative, even if that is not a direct dependency.

Gabriella439/turtle#446 (comment)


Having written these down, I think I don't find them that convincing. In fact, the problems could all be fixed by getting the upstream package that actually has a direct dependency to put in more restrictive bounds and do a release. The issue is really just that it can take a while to do that, and until you do you can end up being in the annoying position of having to tell all your downstream users "you need to add X constraints to your cabal.project".

@Bodigrim
Copy link
Collaborator

Bodigrim commented Dec 23, 2023

In fact, the problems could all be fixed by getting the upstream package that actually has a direct dependency to put in more restrictive bounds and do a release.

Does it need a release though? Would not a revision be enough?

I think a revision of foo-processor to disallow foo-parser-1 would be enough - surely we do not want a buggy version to appear in any build plans.

(2) is more complicated, indeed the most permissible solution requires something like Gabriella439/turtle#447, but it's also possible to restrict bounds to ansi-wl-pprint >= 1.0, optparse-applicative >= 0.18 in a revision.

@michaelpj
Copy link
Collaborator Author

Yes, I think in most of these cases a revision would be fine. You could imagine a more complex situation: perhaps both foo-parser-1 and foo-parser-1.0.0.1 are buggy in different ways and foo-processor doesn't want to force downstream to pick a buggy version.

In fact, that suggests a third case:

  1. Indirect dependencies have major behavioural changes

Suppose that foo-parser-2 changes the behaviour in some significant non-backwards-compatible way. foo-processor is able to support both foo-parser-1 and foo-parser-2 through CPP or otherwise. But my-pkg really only works with the foo-parser-1 behaviour.

An example from the wild might be aeson-1 vs aeson-2: imagine that foo-processor worked with both via CPP, but had a function that returned the HashMap/KeyMap part of an Object. Then my-pkg might expect to be able to operate on the HashMap, but would break if it gets a KeyMap. So we have an indirect requirement to use aeson-1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants