-
Notifications
You must be signed in to change notification settings - Fork 691
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
Proposal for provides
-mechanism
#3061
Comments
I'm a bit wary of the
For these reasons, I'd be much more inclined to support a |
Well, the vocabulary issue can be addressed by maintaining a dictionary with descriptions in Hackage (which is validated against on package uploads). This dictionary could be maintained by hackage trustees. Hackage would be able to list all package/versions which As for the granularity, if you have a dictionary with descriptions, you don't need to enumerate each single instance. You could group into logical units. In a couple of years we may have a proper solution with backpack (@ezyang, right? :-) ) , but we need a solution now and independent of package-sets (a feature that isn't available either yet), as the install-plans are starting to decay now, and I see no way to fix the meta-data properly. As for having to replicate CPP at the Finally, the |
It's not clear to me how flexible this solution is. For example, suppose I am a package author that wants to export an orphan instance. Do I need to ask the Hackage maintainers for a string token first? If such a string token exists, how would I look it up easily? (there are some pretty strange-looking instances out in the wild, after all). If I fail to discover an existing instance string token and upload my package with a different, unapproved token, would my package be rejected? Would its We'd also need to be wary of different datatypes with the same name. For example, both
That sounds like a good idea. (For my needs, it will probably be impossible to come up with a coherent group of tokens due to the sheer number of GHC version differences, but
You're right, I didn't read the phrase "don't interoperate" closely enough. And it's true the |
|
Minor clarification, currently I mostly test the "otherwise unconstrained" solutions the cabal solver comes up with (when only constraining pkg, pkg-version, and GHC version, but nothing else) for the primary package report matrices. However, that solution can easily shift into a different optimum with the slightest additional constraint. Also, if a package is built being a build-dependency of another packages, this provides us often yet another point in the configuration space. And the solution become even more interesting, if I start varying a single dependency (by forcing a specific version of that package) to test whether lower/upper bound for a single dependency are accurate. And the plan is to try to sample more such points in the configuration space than matrix.h.h.o does currently... |
|
I agree with @nomeata and @ezyang that this looks more like a mutual exclusion mechanism than APT's virtual packages. So
Would be nice if @kosmikus could comment on this. BTW, APT also supports specifying conflicts between packages, so maybe it's not too bad?
I think that this feature will be used relatively rarely and only by experts. As an end user, I never found |
That's a very interesting option that might be worth its own subproposal. @hvr, would a |
In the contrary, we need some facility (be it
That would only help for packages that directly depend on both. There are a lot of packages that depend on @RyanGlScott So here's what we'd need to do for the simple case of make sure all
Now,
If it turns out there's another package defining such orphan instances, this would result in 3 more However, I'm not sure how easy this is to implement, as the solver would need to take into account the meta-data of already installed packages and honour their |
Actually virtual packages might make sense for library authors. If the naming of (orphan) instance providers is somehow standardised, then as a library author I could depend on |
While chatting with hvr on IRC, I came up with a solution to this problem that relies only on existing Cabal features. Lets call it the “empty mutex package solution” in the further discussion. Remember that we want to prevent an install plan that has
We can enforce that by uploading a package Then This clearly avoids the problematic situation, works without new features in Cabal, and hence even works with old versions of Cabal. The downside is an empty package installed in some install plans, and that hackage would have to allow such metadata edits on existing packages (including adding a flag and new dependencies). |
@nomeata Your comment as well suggests that virtual package approach might be good way to solve this problem. Having concrete package is a backwards compatible thing, but Hackage could provide stubs for old Yet One more use case for virtual packages: Moving modules from package to another build-depends: virtual-module-data-semigroup module MyModule where
import Data.Semigroup |
Right. But can we, just to avoid confusionwith what Provides mean in other packaging contexts, call this
We should be careful not to reinvent Backpack here.. :-) |
Another idea from IRC. Solve this problem properly and semantically explicitly. Let’s call this in the “orphan instance declaration approach”.
It is quite similar to the Pros: It makes sure that the metadata is in place in every involved package, even before you know that there might be another package providing the same orphan instance. It makes authors aware of orphan instances, and nudges them to avoid them. Cons: Needs changes to Cabal, adds more manual chores to authors. Might be tricky to get a suitable syntax for the description of the orphans (What about qualified package imports? What if the home module of a type (a usually hidden information) changes?) (I’m not particularly fond of that approach, just including it for completeness.) |
I am more than happy for you guys to explore the design space here! As it stands, Backpack has very little to say about how explicit interfaces are supposed to integrate with the dependency solver. It's all new ground for us. |
There's a "Subscribe" button on the right side of the page. |
For some weird reason it always shows up as "Unsubscribe" even when I'm not receiving notifications (other than seeing posts on the main GH page.) Not sure why. I guess I could try going the Unsubscribe->Subscribe route next time... |
Just an update to inform you and document how the specific case of @RyanGlScott uploaded a
Also, So now we can, at least in the case of |
Another minor update, here's a similiar current-tech workaround for the network-uri/network case: |
Problem Statement
Currently there is no satisfying way to express packages which
conflict with each other in the same install-plan.
Some limited form of conflicts can be expressed when two packages
depend directly on each other via
build-depends
relations.However, this is not enough to handle cases where it is necessary to
make sure that two or more packages are mutually exclusive to each
other.
This the need for such mutual exclusivity occurs when entities which
may need to be unique throughout the install-plan, such as
(desugared-into) typeclasses or relocated orphan instances are
involved.
Motivating Use-cases
Relocating orphan instances into compat-packages
One recent use-case which can't be solved properly currently is the
following:
semigroupoids-4.3
conditionally defines an orphaninstance Foldable (Either a)
(forbase<4.8
)base-4.8
,base
started providinginstance Foldable (Either a)
base-orphans-0.1
started equally providing an such an orphan instance likesemigroupoids-4.3
semigroupoids-5.0
now depends onbase-orphans
However, there's currently no way to express that the combination
base >= 4.8
semigroupoids < 5
, andbase-orphans
is forbidden to occur in an install-plan.
Alternative
base
/Preludes
replacements with incompatible typeclass hierarchiesThis use-case refers to a future not-yet implemented
ExportedRebindableSyntax
extension, which would allow the currentlyin scope
Prelude
module to export desugaring rules for things likedo
-syntax, and therefore allow to provide seamlessHaskell2010
support (with a different
Monad
class different frombase
'sMonad
class) in recent GHCs.Some packages could then opt in to explicitly support the
haskell2010
package by depending onhaskell2010
orbase
conditionally in their
.cabal
file:However, since each package would have their own
haskell2010
flag,which are not synchronised by cabal, there is no way to currently
express that
haskell2010
andbase
are mutually exclusive.Proposed enhancement
Provide a new
provides: <string-token>
declaration (allowedeverywhere a
build-depends:
declaration is currently allowed).The
<string-token>
would denote a token in a global namespace whichat most one package selected in a given install-plan may provide.
Application for orphans scenario
This way,
semigroupoids-4.3
's cabal file could be edited and have aLikewise,
base-orphans
(and possibly other packages such asbase-compat
which also contain such orphans) would declareprovides: orphans-base-foldables-either
as well in their respective.cabal
files.Application for
base
/Prelude
replacementsbase.cabal
simply declares something likeand every other package which provides a
base
library which replacesthe core primitives (i.e. core typeclasses, and other entities
wired-in into the language via desugaring rules) and therefore don't
interoperate with
base
would state the sameprovides
declaration.Alternative
constraint
-mechanismOnce could allow to declare
constraint:
properties in.cabal
files.This way, the respective
base-orphans
package versions could startdeclaring all package version ranges containing orphans that were
adopted into
base-orphans
, e.g.base-orphans.cabal
could specifyor dually,
semigroupoids.cabal
(for semigroupoids-4.3 and otherversions affected) could declare
if there is no
orphans-base
version compatible withsemigroupoids-4.3
, and thereforeorphans-base
is incompatible.However,
constraint
is very powerful. than the proposedprovided
-mechanism. Being more general, this may be more complex toimplement in the solver. Moreover, when abused it can result in
confusing install-plan results.
Finally, when modelling the situation where more than 2 packages need
to be mutually exclusive, expressing this in the
constraint
-formulation becomes more complicated and doesn't, as eachinvolved package needs to know about all other conflicting
packages. Specifically the
base
-replacements use-case with multiplepackages becomes impractical to express.
The proposed
provided
-mechanism is weaker, makes it easy to expressmutual exclusivity among N packages, and is IMO easier to implement
as well as easier to reason about.
Alternative
conflicts:
-mechanismDuring the discussion a variant of
constraint:
was suggested, specifically to express conflicts directly viaconflicts:
which denotes the inverse ofconstraints:
. I.e. rather than sayingone specifies
which is easier to reason about for the use-case of specifying conflicting package versions.
Alternative
orphan-instances:
-mechanismThis would be a variant of the
provides
mechanism specialised to orphan instances, by providing a machine-verifiable (i.e. tooling can help making sure the enumeration is accurate) enumeration of orphan instances provided by a package.See #3061 (comment)
/cc @kosmikus @ezyang @dcoutts @nomeata @bergmark @23Skidoo @ttuegel @RyanGlScott
The text was updated successfully, but these errors were encountered: