commercialhaskell / commercialhaskell/stack

Don't record VersionRange for dependencies

Open
#3,723 7 comments 0 reactions 0 assignees View on GitHub
component: build type: discuss
Dominant language
Haskell
Stars
4.1k
Forks
850
Avg merge
10h 37m
Merged PRs (30d)
4

Description

I was always under the impression that in Stack, we take the idea, "One package, one version!" very seriously. So imagine my surprise when I was reading the Stack source code and I noticed the following strangeness in its definition of `Package`:

```
data Package =
...
,packageDeps :: !(Map PackageName VersionRange) -- ^ Packages that the package depends on.
,packageTools :: !(Map ExeName VersionRange) -- ^ A build tool name.
```

Why does Stack need to know the `VersionRange` here? This seems inconsistent with the "One package, one version" philosophy. Boldly, I decided to delete this information and see what happened.

Here were the major places where this information was being used in a nontrivial way:

- `depsPresent` uses the version range to do a check against the `InstalledMap` (a map from package name to information--one version assumption!) to see if we should actually accept the installed package or not.
- `checkPackageBuildPlan` uses the version range to see if version bounds of a package were actually satisfied by its dependencies.
- `addPackageDeps` uses the version range to decide if a package selected by `addDep` is acceptable. But even if it's not acceptable, there are two cases where it can overrule the decision: if `allow-newer` was passed, or if the snapshot implicitly states that the version combination is acceptable
- `withSingleContext` uses the version range to select version dependencies from the `mdeps` argument. I am not sure when multiple instances of the package could ever show up here (violation of the one version principle), so it seems like defensive coding that was added when custom setup support was added. Maybe @mgsloan remembers what's going on here.

To summarize, Stack never actually uses the version range to pick between multiple possible choices (except the Setup case, but I think that's impossible); instead, it uses it to do various consistency checks and slap the user on the wrist if they try to use a package whose dependency bounds don't match.

So, let me suggest something radical: **why don't we just drop all of these checks.** The version bound purists can add some sort of lint which checks if your install plan has inconsistent version ranges and lets the user know if the version ranges are not right... but it seems to me that it would be much simpler if Stack internally *trusted* in the snapshot (and the user extensions). I feel this would also reduce a lot of the friction with version bound updates and Hackage revisions, since a bound update wouldn't actually stop Stack from working (Stack *already* has special case code to trust snapshot versions, and I think that's exactly what you should do; go further!)

CC @snoyberg

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.