qualified imports, PVP and so on

Michael Snoyman michael at snoyman.com
Wed Feb 26 09:45:40 UTC 2014


On Wed, Feb 26, 2014 at 11:05 AM, Herbert Valerio Riedel <hvr at gnu.org>wrote:

> On 2014-02-26 at 06:45:30 +0100, Michael Snoyman wrote:
> > On Wed, Feb 26, 2014 at 12:52 AM, Herbert Valerio Riedel wrote:
> >> On 2014-02-25 at 21:38:38 +0100, Michael Snoyman wrote:
> >>
> >> [...]
> >>
> >> > * The PVP itself does *not* guarantee reliable builds in all cases.
> If a
> >> > transitive dependency introduces new exports, or provides new
> typeclass
> >> > instances, a fully PVP-compliant stack can be broken. (If anyone
> doubts
> >> > this claim, let me know, I can spell out the details. This has come
> up in
> >> > practice.)
> >>
> >> ...are you simply referring to the fact that in order to guarantee
> >> PVP-semantics of a package version, one has to take care to restrict the
> >> version bounds of that package's build-deps in such a way, that any API
> >> entities leaking from its (direct) build-deps (e.g.  typeclass instances
> >> or other re-exported entities) are not a function of the "internal"
> >> degree of freedoms the build-dep version-ranges provide? Or is there
> >> more to it?
> >
> > That's essentially it. I'll give one of the examples I ran into. (Names
> > omitted on purpose, if the involved party wants to identify himself,
> please
> > do so, I just didn't feel comfortable doing so without your permission.)
> > Version 0.2 of monad-logger included MonadLogger instances for IO and
> other
> > base monads. For various reasons, these were removed, and the version
> > bumped to 0.3. This is in full compliance with the PVP.
> >
> > persistent depends on monad-logger. It can work with either version 0.2
> or
> > 0.3 of monad-logger, and the cabal file allows this via `monad-logger >=
> > 0.2 && < 0.4` (or something like that). Again, full PVP compliance.
> >
> > A user wrote code against persistent when monad-logger version 0.2 was
> > available. He used a function that looked like:
> >
> > runDatabase :: MonadLogger m => Persistent a -> m a
> >
> > (highly simplified). In his application, he used this in the IO monad. He
> > depended on persistent with proper lower and upper bounds. Once again,
> full
> > PVP compliance.
> >
> > Once I released version 0.3 of monad-logger, his next build automatically
> > upgraded him to monad-logger 0.3, and suddenly his code broke, because
> > there's no MonadLogger instance for IO.
> >
> > Now *if* the program had been using a system like "cabal freeze" or the
> > like, this could have never happened: cabal wouldn't be trying to
> > automatically upgrade to monad-logger 0.3.
> >
> > Will this kind of bug happen all the time? No, I doubt it. But if the
> point
> > of the PVP is to guarantee that builds will work (ignoring runtime
> > concerns), and the PVP clearly fails at that job as well, we really need
> to
> > reassess putting ourselves through this pain and suffering.
>
> From my point of view, I'd argue that
>
>  a) 'persistent' failed to live up to the "spirit" of the PVP contract,
>     i.e. to expose a "contact-surface" which satisfies certain
>     invariants within specific package-version ranges.
>
>
How would persistent have done better? AFAICT, the options are:

1. Do what I did: state a true version dependency on monad-logger, that it
works with both version 0.2 and 0.3.
2. Constrain it to one or the other, which would be a falsehood that would
restrict users' ability to use the package.

Let's try it a different way. If transformers removed a MonadIO instance
between version 2 and 3 of the library, should that mean that every single
package with type signatures involving MonadIO should be constrained to one
specific version of transformers?


>  b) However, the PVP can be blamed as well, as in its current form it
>     doesn't explicitly address the issue of API-leakage from transitive
>     build-dependencies. [1]
>
> The question for me now is whether the PVP is fixable in this respect,
> and at what cost.
>
> Moreover, it seems to me, it always comes down to type-class instances
> causing most problems with the PVP (either by requiring version-bump
> cascades throughout the PVP-adhering domain of Hackage, or by their hard
> hard to constraint leakage through package module/boundaries); maybe we
> need address this issue at the language-level and provide some facility
> for limiting the propagation of type-class instances first.
>
>
There's one other issue, which is reexports. As an extreme example, imagine:

* Version 1 of the foo package has the Foo module, and it exports foo1 and
foo2.
* Version 2 of the foo package has the Foo module, and it exports foo1.
* Version 1 of the bar package as the Bar module, defined as:

module Bar (module Foo) where
import Foo
* According to the PVP, the bar package can have a version bound on foo of
`foo > 1 && < 2.1`.
* User code that depends on foo2 being exported from Bar will be broken by
the transitive update of foo.

The example's extreme, but it's the same basic problem as typeclass
instances.

Michael


>
>
>  [1]: An alternative to what I'm suggesting in 'a)' (i.e. that it'd be
>       `persistent`'s obligation), could be that the package you
>       mentioned (which broke due to monad-logger having a non-monotonic
>       API change), might become required to include packages supplying
>       the instances they depends upon in their build-depends, thus
>       turning an transitive dep into a direct dependency.
>
>
I don't think I follow this comment, sorry.


> Cheers,
>   hvr
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/libraries/attachments/20140226/55679bb2/attachment-0001.html>


More information about the Libraries mailing list