@TeofilC I want to highlight these two points from your comment:
We rely on a lot of volunteer work. Especially a lot in the ecosystem of maintainers diligently looking after packages. Often in their spare time. And even if you are being paid to work on Haskell, package maintenance might not be on your job description.
In my opinion, being cautious and mindful of the downstream impact changes have goes a long way towards this. Getting a warning or deprecation notices that informs the user of the necessary changes reduces the burden to figure out what
Often times the breakage is not obvious. Taking the example I posted, the error messages are barely helpful.
Error 1:
Broken.hs:21:21: error: Operator applied to too few arguments: !
|
21 | data X a = X { s :: ! a }
| ^
what arguments are missing? I guess I could try to just remove the space? But the error doesn’t say: “did you intent to use a strictness annotation !a?”. After all BangPatterns
is enabled.
Error 2:
Broken.hs:31:10: error:
• Non type-variable argument in the constraint: MonadError D m
(Use FlexibleContexts to permit this)
• In the instance declaration for ‘C m T’
|
31 | instance MonadError D m => C m T where
| ^^^^^^^^^^^^^^^^^^^^^^^
this one is actually quite good. It tells you that you need FlexibleContexts
here. It doesn’t say that this used to be implied by UndecidableInstances
though, which would have been helpful. (Fun fact: this error will not happen if you don’t have Haskell2010 enabled, something you might just have in your codebase because the stock cabal file contained the language stanza).
Error 3:
Broken.hs:38:10: error:
Variable not in scope: (@) :: (String -> a0) -> t0 -> t1
|
38 | h = read @ Int "5"
| ^
Broken.hs:38:12: error:
• Illegal term-level use of the type constructor ‘Int’
imported from ‘Prelude’ at Broken.hs:14:8-13
(and originally defined in ‘GHC.Types’)
• In the second argument of ‘(@)’, namely ‘Int "5"’
In the expression: read @ Int "5"
In an equation for ‘h’: h = read @ Int "5"
|
38 | h = read @ Int "5"
|
Pretty much as unhelpful as (1).
Error 4:
Broken.hs:36:5: error:
• No instance for (Data.Bifunctor.Bifunctor Y)
arising from a use of ‘bimap’
• In the expression: bimap id id Y
In an equation for ‘g’: g = bimap id id Y
|
36 | g = bimap id id Y
| ^^^^^
This one is so-so. It claims no instances was found, though the code to derive the instance is clearly there. It does not give any hint that there are now new staging/ordering restrictions.
The point I’m trying to highlight here (to exemplify @TeofilC’s first point) is that on a codebase with lots of code, you might not have written and are not intimately familiar with (someone else wrote that code, and maybe yet someone else reviewed it, and now you are spending your time looking at errors …), it is increasingly hard to decipher what’s wrong, and what the appropriate fix is. Especially if the file is multiple hundreds of lines.
While this thread might look like I’m complaining that GHC keeps breaking a production codebase, I don’t even think that’s the worst. There are people who are paid to look at this. What about all those poor folks who maintain packages in their spare time. Is their time best spent on dealing with continuous churn? I’d love to help out! If you are paid to work on a haskell codebase, and can trivially test that codebase against a recent compiler, instead of waiting until everyone else has done the work for you, you could proactively help migrating packages you rely on. This all however can only work if you can just swap out the compiler trivially.
As I’ve alluded to before, experience over the last years has been that there is little point in trying a compiler for any serious project before we haven’t hit at least .4
, too much is simply broken hard, and simply won’t compile. Without using the compiler, no one will know about all the migrations necessary.