Skip to content
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

Amend GHC2024 proposal to specify phased introduction #632

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

adamgundry
Copy link
Contributor

As discussed here, making GHC2024 the default language edition will break programs that do not specify a language edition. This amendment proposes a phased introduction of GHC2024 and a new warning, in the interests of stability.

Time is short before the GHC 9.10 fork date so I would appreciate prompt feedback on this idea. We could decide to accept the breakage, on the basis that most users will specify a default-language in their Cabal file, but this should be an explicit choice.

Rendered.

@adamgundry adamgundry mentioned this pull request Jan 24, 2024
Comment on lines 70 to 72
language edition do not affect their code. It does mean that throw-away uses of
``ghc M.hs`` will emit a warning by default; one way to avoid this is to define
an alias, e.g. ``alias ghc21='ghc -XGHC2021'``. Users of ``ghci`` may be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm conflicted.

I don't like this. But script calling ghc are likely to be the most common reason for no language edition being specified. So we need this behaviour for the proposal to be useful.

Is it worth the developer time that we'd put in it? I guess I'm kind of against this warning then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure too. I doubt the implementation effort will be that much, but it feels quite heavy-handed to issue so many warnings. Moreover, @simonmar recently pointed out in another context that warnings don't necessarily help, e.g. existing scripts may well run unattended, with nobody paying attention to warnings they emit, and only resolving issues when the breakage occurs. So perhaps it is enough to explain in the release notes and migration guide the need to specify GHC2021 explicitly?

@angerman I'm interested to know what you think about this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm against changing the default without informing users it will change.

If people don't read the warnings, it will break either way, not or later.
For those that do read the warnings (and this might just come from running runghc or building something by hand, and those looking at (new) warnings in CI), this will help them make decisions about upgrading and adjusting easier.

The work involved for downstream users is the same, but the abrupt breakage is much more hostile than a gentle warning informing about the upcoming breakage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm against changing the default without informing users it will change.

Is informing users in the user's guide / release notes / release announcement adequate? What if we ship 9.10 with GHC2024 available but not the default, and change the default in the subsequent release, accompanying both releases with publicity for this plan (but not warnings by default)?

I realise that not everyone reads the release notes. But not everyone reads warnings either! And the alternative means warning for every one-off module forever, for the corner cases where somebody uses ghc (but not cabal) for a long-lived script and doesn't specify the language edition.

@simonpj
Copy link
Contributor

simonpj commented Jan 29, 2024

I believe that our general plan is that

  • We want to encourage every bit of source code to specify its language edition (via a cabal file, or LANGUAGE pragma, or .ghci file)

That makes the code self-describing, and robust to subsequent GHC upgrades. If that is what we want, then it seems sensible to have a warning that encourages people to do so.

But it occurs to me that if everyone specifies the edition then it makes no difference whether or not GHC has a "default" edition. It would be fine for its default edition to stay at GHC2021 forever. The default edition has no effect if you specify an explicit edition.

I think the motivation for the default edition was that is the language you get by default. But now you'll immediately get a warning saying "please specify a language edition"!

Hence question: why change the default edition at all, ever? (Saying "you don't get the warning in ghci seems like too narrow an exception to justify the idea.)

@nomeata
Copy link
Contributor

nomeata commented Jan 29, 2024

We want to encourage every bit of source code to specify its language edition (via a cabal file, or LANGUAGE pragma, or .ghci file)

That wasn’t quite my idea. My idea is that

We want to encourage every long-lived piece of source code to specify its language edition (via a cabal file, or LANGUAGE pragma, or .ghci file, or implicitly by pinning GHC)

My two changes are

  • long-lived. This excludes playing around with ghci, one-off scripts, online REPLs for experimentation. These use-cases (unfortunately) also don’t really do well with warnings.

  • less importantly, but I think it’s also valid to build programs in a hermetic environment and using a pin on GHC’s version as indication for all the things, and where are not surprised by breakage when they upgrade the pin (whether due to changes to GHC or the libraries implied by that). It’s a bit like we encourage everyone to be meticulous and explicit with their cabal dependency bounds, but in environments where you simply pin down your package set in your environment, and you are not producing libraries for others, that’s just busywork.

Ok, the second is maybe a bit of a distraction; the first one is worth discussing: Do we want the default, out of the box behavior to be an historic path-dependent artifact, or the latest and greatest?

@simonpj
Copy link
Contributor

simonpj commented Jan 29, 2024 via email

Comment on lines 48 to 49
primarily because of ``MonoLocalBinds``. While Cabal packages will usually
specify a ``default-language`` and hence be unaffected, this is not guaranteed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cabal packages that don't specify a default-language default to Haskell98. At least this is Cabal's current behaviour. Moreover, in light of this discussion and the last Cabal dev meeting, I believe this won't change (i.e. Cabal packages without a default-language will always default to Haskell98. Perhaps @gbaz can concur.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cabal packages that don't specify a default-language default to Haskell98

Ahh... I didn't know that. So if the .cabal flag doesn't specify a language edition, you get ghc -XHaskell98. That's fine; from GHC's point of view, it is as if every package compiled with Cabal specified a language edition, so it doesn't matter what GHC's default language edition is.

Where is this documented?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this documented?

Not in the cabal documentation, apparently: https://cabal.readthedocs.io/en/3.10/cabal-package.html#pkg-field-default-language

Copy link

@alt-romes alt-romes Jan 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is undocumented at the moment (tracking ticket), but here is the source line that dictates this behaviour

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's good news! I thought an empty default-language would simply not pass anything to GHC and thus use the default. Big relieve, this means that everyone using .cabal gets to benefit from the intended stability guarantees, and we have to worry here only about those using GHC without .cabal.

@nomeata
Copy link
Contributor

nomeata commented Jan 29, 2024

long-lived. This excludes playing around with ghci, one-off scripts, online REPLs for experimentation. These use-cases (unfortunately) also don’t really do well with warnings.

    • Fine -- but I do not know how to tell GHC that a bit of code is long-lived. How could we turn this bullet into something actionable? - - -

The actional bit for the users is to specify GHC20xx when they want to be able to upgrade ghc without causing immediate churn; as promised in our documentation.

The actional bit for us could either be

  • Introducing careful warnings and release notes, hope that affected people see them, and still eventually break the cases where people didn't see it.
  • Change the default right away, don’t bother with the question of which users should see the warning, and all those who don’t already specify an extension (typically through .cabal) and are affected, will notice the breakage. But that doesn’t mean we force them to upgrade to NoMonoLocalBinds immediately – they can just slap -XGHC2021 on then.
    • I'm afraid I could not parse this at all. I have no idea what "implicitly by pinning GHC" means. Perhaps you can be more explicit?

Sorry; what I mean is setups where I build a Haskell applications, and my whole dev and CI environment is set up to not randomly upgrade GHC or libraries (using cabal freeze files, nix derivations etc), but instead precise versions are configured. In such a setup, it can be a bit silly to additionally specify information like cabal version ranges or GHC language editions, because that’s already implied. And some users of such a setup (I, probaby) am probably happy with simply always using GHC’s latest default language, and would rather fix all breakage as I upgrade in one step than upgrade, figure out if there is a new language edition, update my build scripts to set it.

But nevermind this use-case, it’s probably a corner case and need not guide this discussion.

@simonpj
Copy link
Contributor

simonpj commented Feb 2, 2024

Hence question: why change the default edition at all, ever? (Saying "you don't get the warning in ghci seems like too narrow an exception to justify the idea.)

No one has responded to this question.

@nomeata
Copy link
Contributor

nomeata commented Feb 2, 2024

How about: To provide contemporary Haskell by default when using ghci interactively, or when experimenting with little un-cabalized files. I was hoping that contemporary Haskell is opt-out, not opt-in.

@simonpj
Copy link
Contributor

simonpj commented Feb 2, 2024

How about: To provide contemporary Haskell by default when using ghci interactively, or when experimenting with little un-cabalized files. I was hoping that contemporary Haskell is opt-out, not opt-in.

But the proposal says

In addition, GHC 9.10 and later releases will emit a warning (controlled by -Wunspecified-language and in -Wdefault) when compiling a .hs file without an explicit choice of language edition. (Compiling a .hs file includes loading it into ghci, but using ghci interactively without specifying a language edition will not emit a warning.)

So these "un-cabalized files" will attract warnings; we are thereby encouraging users to put language editions on un-cabalized files, which is arguably good because it specifies the language edition. But that leaves only ghci. And I think that the spec above means that if I'm in ghci and say ":load Foo.hs" then Foo.hs needs an explicit language edition. So it's only expressions typed into the prompt. That is a pretty narrow use-case for having a default language at all.

A big advantage of not having a default language is that the base language remains fixed at all times; always Haskell98 or something. So the problem addressed by this MR, that upgrading to a new version of GHC might break your build, goes away.

I'm not pushing hard here, just pointing out that having a default language edition that changes

  • Has very narrow benefits (ghci expressions only)
  • Causes breakage problems that that then need to be mitigated with warnings and deprecation periods

@nomeata
Copy link
Contributor

nomeata commented Feb 2, 2024

Right – after all I prefer the original plan, and not this proposal.

But I agree with your analysis: Before we make simply running ghc spew warnings, and introduce the compexity of when to warn when loading a file from ghci, it may be better to just give up the idea of an evolving out-of-the-box experience, and freeze the default at GHC2021 forever.

@adamgundry
Copy link
Contributor Author

Thanks @simonpj, that's a helpful analysis. I'm increasingly convinced that the I warnings proposed here are the wrong approach.

I think it's plausible to say:

  • GHC2024 becomes available for users who opt in.
  • GHC2021 remains the default for now.
  • Users are encouraged to specify their language edition explicitly (maybe with a warning in -Wcompat?), but not nagged if they don't (i.e. no warning in -Wdefault).
  • If we want to shift the default in the future, we can think about more targeted warnings and longer deprecation periods (e.g. warning if you rely on NoMonoLocalBinds and don't specify a language edition). But we don't have to do that now; we can see how GHC2024 is received first.

@aspiwack
Copy link
Contributor

aspiwack commented Feb 2, 2024

For what it's worth, I strongly want ghci to give me the latest language edition by default. I realise that adding the right edition is only one line. But it's a silly line. Which adds a non-trivial amount of friction to running ghci.

I also believe that having and old edition of GHC as default in ghci sends the entirely wrong signal. We're thinking about stability a lot. I'll sound like a broken record, here, but it's important, for the sake of stability that GHC's default and GHC's normal mode of operations are roughly aligned. Otherwise we're blurring the lines between experimental(ish) where you should think carefully before using, and standard where we have your back.

@tomjaguarpaw
Copy link
Contributor

I'm a bit confused by this @aspiwack. Suppose I have some code that works in GHCi X but that doesn't work in GHCi (X + 1), because the latter changed to latest language edition, GHC20AB, by default and my code is incompatible with GHC20AB. That sounds like lack of stability to me. But it sounds like you're saying it's important that GHCi (X + 1) change to GHC20AB by default because that promotes stability. Could you explain what you're thinking of?

@aspiwack
Copy link
Contributor

aspiwack commented Feb 2, 2024

@tomjaguarpaw sure. I claim that stability is largely a social process. Why does Haskell have a reputation of being more unstable than, say, Ocaml? As someone who maintains software in both ecosystems, I'm pretty sure that the answer is not technical both break with similar paces. The reason, I claim (I'm claiming a lot today), is that Haskell programmers live more dangerously than Ocaml programmers, using more corners of the language that are more likely to break.

Part of the reason is that there are simply more such corners in Haskell, Ocaml being more conservative with how it gets extended. This isn't going to change: it's part of the value proposition of Haskell to be open to new ideas and drive the future of programming languages. But because there's such a disconnect between default Haskell and normal Haskell, every Haskell file out there starts with a dozen extension added. This habituates Haskell programmers to consider that adding an extension is benign. So when an error message suggests adding an extension (a good thing for discoverability), they don't think twice and add it to their file's header. Even if it was a bad idea.

My strongly held belief is that we should make strong efforts to make it so that adding extension isn't normal. This will let us manage much better the (necessary) boundaries between stable and unstable.

(similarly, I believe that the default language with cabal init or stack new should be the latest language edition allowed by the compiler being used)

@gbaz
Copy link

gbaz commented Feb 2, 2024

My feeling is that there are certain rupture points where we can bump the default language edition -- perhaps first-component releases of ghc -- e.g. from 9 to 10 or 10 to 11, and in between ghc should stick to a fixed default language edition.

That said, we can evolve what cabal init initializes the explicit language edition to more frequently, and that can be a way to encourage forward progress...

@tomjaguarpaw
Copy link
Contributor

I claim that stability is largely a social process

I too think this is true. I think that formalising exactly the stability guarantees we want to adhere to is going to be rather tricky. Different people can reasonably have different ideas of what is meant by "stability". "Stability" roughly means "the future is the same as the past" and different notions of "the same" lead to different notions of "stability". For one person "the same" might mean "if I run the same code with a new GHCi it runs in the same way" but for another person "the same" might mean "each GHCi release has the same property: it comes with the latest GHC20AB by default". Put another way, does stability require staying in the same place, or moving with constant velocity also stability?

In this particular case of default language edition for GHCi I don't think I agree with you. I'd prefer defaults not to be bumped. But in general I agree it's not too obvious exactly what it is that we should try to stabilise to provide maximum benefit for Haskellers.

@aspiwack
Copy link
Contributor

aspiwack commented Feb 5, 2024

@gbaz

My feeling is that there are certain rupture points where we can bump the default language edition -- perhaps first-component releases of ghc -- e.g. from 9 to 10 or 10 to 11, and in between ghc should stick to a fixed default language edition.

I'm fine with this, as long as we change the first component every 3 years or so 🙂 .

@tomjaguarpaw

But in general I agree it's not too obvious exactly what it is that we should try to stabilise to provide maximum benefit for Haskellers.

Indeed. I don't claim to know the future. I'm just guessing with a loud voice.

@adamgundry adamgundry added the Pending committee review The committee needs to evaluate the proposal and make a decision label Feb 15, 2024
@adamgundry adamgundry self-assigned this Feb 15, 2024
@adamgundry
Copy link
Contributor Author

This proposal has been discussed further by the committee, and there seems to be general agreement that:

  • ghci should default to a recent language edition.
  • Modules compiled using ghc should ideally specify their language edition, either in the file itself or via Cabal.

However it is less clear what to do about modules that do not specify a language edition. Some options:

  1. Silently use the latest language edition. This is good for ad hoc use, but will sometimes lead to breakage in non-Cabalised code when the user upgrades their compiler. Users can be advised to specify a language edition (e.g. in release notes).
  2. Fix a default language edition for modules (presumably either Haskell98, Haskell2010 or GHC2021) and plan never to change it. This is somewhat inconsistent with ghci using the latest language, less good for ad hoc use, and may be difficult to maintain indefinitely. But it is very good for stability, and perhaps if the default is (e.g.) Haskell98 then users will be motivated to explicitly specify something more modern.
  3. Fix a default language edition based on the compiler supermajor version (e.g. so GHC 9.x uses GHC2021 (at least for x>=2), and GHC 10.x could use GHC2024); do not bump the default with other releases.
  4. Issue a warning nagging the user to choose a language edition, but continue with a default language following one of the above options.
  5. Refuse to compile the module without a language being specified.

Further ideas or feedback on these options is welcome.

@gbaz
Copy link

gbaz commented Mar 26, 2024

I vote for 1 combined with 4.

In particular, silently use the latest language edition. However, on any error at all, also add to the errorspew a general warning that users should fix a language edition, and that the error may be caused by not specifying a language edition.

@angerman
Copy link
Contributor

I'm in the same boat as @gbaz. 1+4. If you don't pin your expectations, then don't expect any pinned behaviour.

@adamgundry
Copy link
Contributor Author

on any error at all, also add to the errorspew a general warning that users should fix a language edition, and that the error may be caused by not specifying a language edition.

Thanks, this is a nice idea. The argument against 4 has always been that it is too much nagging to emit a warning on every compilation. But showing the message only if an error occurs anyway sounds much more reasonable.

@adamgundry adamgundry added Needs revision The proposal needs changes in response to shepherd or committee review feedback and removed Pending committee review The committee needs to evaluate the proposal and make a decision labels Apr 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs revision The proposal needs changes in response to shepherd or committee review feedback
Development

Successfully merging this pull request may close these issues.

None yet

8 participants