6

The Haskell Tool Stack is the most popular Haskell package manager for now, it's main goal is to make building haskell packages reproducible.

But the way stack approach it's goal is to find a huge no-conflict-set of package-revisions, and call it snapshot. In this way, the package maintainer is pushed to update his packages' dependencies so that it will not conflict with the recent snapshot.

I have to say, this design is too ideal to work in the real world.

For comparison, NPM (the package manager of NodeJS) approaches this goal via a more practical way: it allows redundancy. In diamond-rely-on case such as a -> b, c; b -> d(v1); c -> d(v2), NPM just install two different version of d separately for b and c. This way, users who using packages can depending on a package like a blackbox, no need to consider if there is conflicting-deep-dependencies between it's dependences.

I'm wondering is there some practical reason why Stack is not designed to allow redundant revisions of a package. Is it possible to implement such a package manager for Haskell? What is the hardest part of it's implementation?

luochen1990
  • 3,689
  • 1
  • 22
  • 37
  • The hardest part is giving in to a broken dependency ecosystem. When each package that relies on a reusable dependency needs its own independent "reusable" copy, you know you have failed hard somewhere. – spectras Jun 14 '19 at 09:48
  • 1
    @spectras Sorry but I can't follow you, could you please give a more detailed description? – luochen1990 Jun 14 '19 at 10:12
  • 2
    The whole point of making re-usable packages is to re-use them. If, when 50 things depend on a package, you end up having 50 copies of the package, like NPM does, your package system failed. What you describe is a broken dependency ecosystem. It is something you want to avoid, not strive for. (Note: I am not blaming NPM itself for the sorry state of JS dependencies, it has to work with what it's given). – spectras Jun 14 '19 at 11:24
  • The practical reason is that Haskell is a compiled language and needs all dependencies to be resolved at compile or link time. You will find the same constraint in C or C++. – Bob Dalgleish Jun 14 '19 at 14:08
  • Can you be more specific about your "this design is too ideal to work in the real world"? What do you believe is stopping it from working? (To my admittedly somewhat naive eyes, it appears to be working pretty well in the very real world we inhabit today.) – Daniel Wagner Jun 14 '19 at 14:23
  • 1
    @spectras If I have to choose between "have copies of different revisions of same package" and "need to use packages careful to avoid diamond-rely-on case", I will prefer the former. And the redurant can be optmized if the package manager is implemented well. – luochen1990 Jun 14 '19 at 16:15
  • @DanielWagner Yes, I mean, the package maintainer is pushed to update his packages' dependencies so that it will not conflict with the recent snapshot, and this makes haskell's ecosystem fragile (a package may be absent from the latest snapshot someday just because the mantainer have no time to update it's dependencies), this makes lot of packages absent from stack, Just have a look at how many recently created Haskell packages choose not using stack. – luochen1990 Jun 14 '19 at 16:25
  • Stack isn't limited to using dependencies which are included in a snapshot. – Jeremy List Jun 30 '19 at 21:12

1 Answers1

4

Yes, it is possible. In fact, cabal used to work that way by default. It was abandoned in the move to nix-style builds, but as far as I know there's no technical problem standing in the way of doing it again.

That said, my experience with nix-style builds is that it is rare to find that forcing each package in the dependency tree to a specific version prevents you from being able to construct a build plan. I'm not sure whether this is so with stack, too -- I don't have much experience with it -- but at least for cabal at the moment there seems little benefit to doing that, and so the simple design with the simpler failure modes seems much more desirable.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380