Exciting times! A lot of people (myself regrettably included) have historically used base bounds as a proxy for “which GHC release is this package compatible with?”. What’s the best way to indicate this moving forward? I suppose once base is genuinely reinstallable it’ll be less of a problem unless you deliberately depend on GHC internals, and sensible PVP bounds for base will get you a working build plan with new compilers?
It is possible for a .cabal file to use conditionals that depend on GHC version, but that isn’t a perfect solution: it can’t be changed retrospectively via revisions, and it may accidentally cause problems for other compilers (e.g. MicroHS) if the constraints assume the use of GHC.
Ideally, we would minimize changes to the semantics of existing language extensions, and would instead add new extensions. That way packages can use other-extensions in their .cabal file to indicate what they need in a declarative way, and (in principle) any compiler supporting those extensions should work. However, not all extensions are well-specified and there are sometimes bugs or compiler behaviour changes meaning packages need to express more fine-grained constraints. Perhaps we should have a notion of versioning for language extensions…
I hope you were joking, but just in case: the compiler version range + the extension exactly specifies the semantics expected of the extension. Of course if the upper boundary is not specified, that would express hope that any future modifications to the language extension would be backward-compatible.
The upper boundary of what exactly? As far as I understood it, one can currently not specify in the cabal file with which compilers/which version of the compiler the package is compatible. People tend(ed) to use the upperbound on ‘base’ for this; but with the plan of decoupling base from ghc that will not work anymore.
Now suppose GHC 10.2 comes up with a new and improved PolyKinds which alas has a corner case that breaks our package. Then we might want to say
if impl(ghc >= 7.5) && impl(ghc < 10.2)
other-extensions: PolyKinds
Unfortunately while this is informative it also does next to nothing, we still need to come up with a workaround for PolyKinds in every affected module and maybe guard it with CPP. But my only point was that it’s semantically correct to equate the “extension version” with extension name + compiler version range, and the latter would be preferable because it doesn’t introduce any new concept.
The issue being that this just enables or disables the extensions enabled instead of giving you version bounds.
You could simulate this by giving impossible build dependencies for certain ghc versions:
if impl(ghc <= 7.5)
build-depends: base < 0
But this wouldn’t be a satisfactory solution since you then can’t use the cabal constraint solver here.
You could add a dependency to the ghc or ghc-internal or ghc-experimental packages, but for most packages these are pointless dependencies, and this obviously wouldn’t work for alternative haskell compilers like mhs.
The point of being able to version extensions would be to distinguish them from the current version of the compiler. In principle it would be nice to be able to say “this program requires FancyExtension-1.0” and any GHC (or other compiler) version that supported FancyExtension-1.0 would continue to work, even if it had also introduced FancyExtension-2.0 with breaking changes in the meantime.
That said, as @hasufell says this risks introducing a lot of complexity, both for users and for compiler implementers. Certainly keeping extensions stable is preferable where possible. But there’s a genuine tension between maintaining stability and wanting to fix deficiencies in existing designs.