qualified imports, PVP and so on

Herbert Valerio Riedel hvr at gnu.org
Wed Feb 26 10:22:01 UTC 2014


On 2014-02-26 at 10:45:40 +0100, Michael Snoyman wrote:

[...]

>> >> ...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?

[...]

>> 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.

Yes, "persistent" itself does in fact work with both major versions of
"monad-logger", but alas the API reachable through depending solely on
"persistent" leaks details of the underlying monad-logger version used.

...but the PVP's primary statement is define how a package shall behave
from the point of view of its users (where by user I mean package
build-depending on `persistent`). So...

> 2. Constrain it to one or the other, which would be a falsehood that would
> restrict users' ability to use the package.

...this is would actually be, what I'd interpret the PVP to
expect/require from "persistent" in order to satisfy its goal to shield
the package's users from incompatible changes.

> 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?

yes, that'd be what I'm suggesting here (the [1] footnote is a different
suggestion for the same problem though)

>>  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:

Yes, I'm well aware of this problem, but that's easier to control, as
you can use explicit import/export lists to constraint what entities you
expose to direct users of your package. That's what I'm doing e.g. in

 http://hackage.haskell.org/package/deepseq-generics-0.1.1.1/docs/Control-DeepSeq-Generics.html

where I'm explicitly naming the entities I re-export from
Control.DeepSeq for convenience. (However, I'm lacking such a facility
for instances)

>
> 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.

[...]

>>  [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.

I'm basically just saying, that the package which used "persistent",
ought to add "monad-logger ==0.2.*" to its direct build-dependencies, as
it depends on an instance provided by monad-logger. The huge down-side
is, that you'd have to know about type-class instances leaked through
persistent, in order to know that'd you have to add some of
"persistent"'s transitive build-depends to your own package, in order to
safe yourself from missing out on type-class instances.


More information about the Libraries mailing list