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

GHC2024 #613

Merged
merged 16 commits into from Jan 9, 2024
Merged

GHC2024 #613

merged 16 commits into from Jan 9, 2024

Conversation

nomeata
Copy link
Contributor

@nomeata nomeata commented Sep 27, 2023

The proposal has been accepted; the following discussion is mostly of historic interest.


Rendered

This PR will guide the process of deciding if we want to have, and then defining, GHC2024, as per the process outlined in #372.

@nomeata
Copy link
Contributor Author

nomeata commented Sep 27, 2023

Fall is coming close, and I’d like to start the process of defining GHC2024.

In last year’s attempt (#559) the vote was not to define a new language edition, but I hope that we can have it now. I still think that we should strive to produce a regular stream of “This is modern haskell” language extensions, given that they do little harm (existing code is unaffected), and we don't want a new language edition release to be something that scares people. At least no more than a GHC release itself.

I hope we can do this without too much entanglement with the extension classificaiton proccess (#601) and the stability guarantee discussion. We should only include extensions that we consider “stable” in some sense, but I hope we can make that call without finalizing the other pieces.

I’ve copied the proposal over from last year, with four suggestions. The committee will eventually vote upon them individually, so including one that doesn't make it shouldn’t affect the other extensions’ prospect.

I invite interested parties who have good arguments for additional changes to submit them as PRs or “suggested edits” against this branch. Committee members can just commit directly. If you have further refinements to the pros and cons of an extension, please also add them.

@adamgundry
Copy link
Contributor

Thanks for kicking this off @nomeata! I have made some small edits and suggested adding DisambiguateRecordFields.

@divarvel
Copy link

Would DerivingStrategies be a good candidate for inclusion in GHC2024? With GND part of GHC2021 I think it makes sense to have a way to be explicit about it.

I personally use it systematically with newtypes and even have contributed a hlint hint to enforce it.

@Kleidukos
Copy link

Agreed, DerivingStrategies is part of the dialect of a number of organisations using Haskell and I can't imagine writing (and publishing) Haskell code without it.

@adamgundry
Copy link
Contributor

I agree DerivingStrategies would be a good addition; I've added it to the proposal text.

@amesgen
Copy link

amesgen commented Oct 4, 2023

Another potential candidate for inclusion: LexicalNegation. It solves a small but very real syntactic anomaly (see the linked examples, or some anecdotal evidence here), and I used it every since it became available and think there is no reason not to enable it everywhere. Still, given that it was introduced in 9.0, it is maybe too young? (OTOH, eg ImportQualifiedPost was added in 8.10 and is already in GHC2021).

@nomeata
Copy link
Contributor Author

nomeata commented Oct 4, 2023

Certainly worth considering! It received few votes in 2021, but maybe just because there were so many extensions considered back then. Do you want to propose concrete wording for the section?

@phadej
Copy link
Contributor

phadej commented Oct 4, 2023

@amesgen

This means that (- x) is the right operator section of subtraction, whereas (-x) is the negation of x.

That is terrible. I don't see that kind of syntax go through in untyped language where there are no types to catch mistakes. But having types doesn't make it a good syntax. I'm not a fan of whitespace sensitive expression syntax. It's already terrible with @. I'd wish GHC steer back to have whitespace insensitive expression syntax (sans layout).

@phadej
Copy link
Contributor

phadej commented Oct 4, 2023

I also opened a GHC issue, https://gitlab.haskell.org/ghc/ghc/-/issues/24062 NegativeLiterals alone can change the meaning of programs. That's a corner case, but I actually used it this month (i.e. cannot use NegativeLiterals).

@amesgen
Copy link

amesgen commented Oct 4, 2023

This means that (- x) is the right operator section of subtraction, whereas (-x) is the negation of x.

That is terrible. I don't see that kind of syntax go through in untyped language where there are no types to catch mistakes. But having types doesn't make it a good syntax. I'm not a fan of whitespace sensitive expression syntax. It's already terrible with @. I'd wish GHC steer back to be whitespace insensitive (sans layout).

Thanks for mentioning that! Just FTR: There are even more operators that are already whitespace-sensitive since proposal 229 (which also introduced LexicalNegation).

In that light, I think it makes sense to still wait until a future iteration of the GHCXXXX process whether there is any movement to go back to whitespace insensitivity in this area, and only to revisit LexicalNegation (hence embracing whitespace sensitivity) if that turned out not to be the case.

@phadej
Copy link
Contributor

phadej commented Oct 4, 2023

any movement

I don't expect any large movement. It feels we are approaching a local optima of the syntax evolution: there is very little one can do without breaking something.

Off-topic: I agree that -identifier and - identifier can be understood as @tyvar and @ opapply, that would be consistent. But then -literal will be different than let x = literal in -literal, but typelet x = literal in Proxy @x and Proxy @literal work the same (if we had typelet, but say emulating with ~` constraint).

So i back up my complaint. I'd say that LexicalNegation without NegativeLiterals make sense, it's consistent with other whitespace sensitivity in GHC (which I don't like, but it's there). NegativeLiterals however break code (it was an opportunity to introduce a class(es) just for literal desugaring, but it was missed: fromNatural for normal desugaring, separate fromInteger for NegativeLiterals - then I could opt my type to not work with NegativeLiterals).

@amesgen
Copy link

amesgen commented Oct 4, 2023

So i back up my complaint. I'd say that LexicalNegation without NegativeLiterals make sense, it's consistent with other whitespace sensitivity in GHC (which I don't like, but it's there). NegativeLiterals however break code (it was an opportunity to introduce a class(es) just for literal desugaring, but it was missed: fromNatural for normal desugaring, separate fromInteger for NegativeLiterals - then I could opt my type to not work with NegativeLiterals).

That makes a lot of sense; I don't know the exact historical details, but judging from

Under LexicalNegation, negated literals are desugared without negate. That is, -123 stands for fromInteger (-123) rather than negate (fromInteger 123). This makes LexicalNegation a valid replacement for NegativeLiterals.

(src) the motivation might just have been for LexicalNegation to be a strict superset of NegativeLiterals? I think proposal 229 does not specify this, and I also don't see any related discussion in the implementation PR.

In that case, maybe LexicalNegation and NegativeLiterals should be made fully orthogonal, ie such that with -XLexicalNegation -XNoNegativeLiterals, -1 desugars to negate (fromInteger 1). But this is getting off-topic for this PR 😄

@nomeata
Copy link
Contributor Author

nomeata commented Oct 10, 2023

We should probably set out a timeline for this process.

I suggest to collect nominations and rationales until the end of October, start the committee discussion November 1st with a vote early December. Hopefully this means the implementation makes it to 9.10.

@adamgundry, you seem to visibly care the most. WDYT?

@nomeata
Copy link
Contributor Author

nomeata commented Oct 10, 2023

Another potential candidate for inclusion: LexicalNegation. It solves a small but very real syntactic anomaly (see the linked examples, or some anecdotal evidence here), and I used it every since it became available and think there is no reason not to enable it everywhere

It seems to be a bit more contentious than initially thought. Do you still want to push for it, or shall we use that discussion bandwidth for something else?

@amesgen
Copy link

amesgen commented Oct 10, 2023

It seems to be a bit more contentious than initially thought. Do you still want to push for it, or shall we use that discussion bandwidth for something else?

No, I think it makes sense to defer discussions on LexicalNegation to a future iteration of GHCXXXX 👍

@adamgundry
Copy link
Contributor

I suggest to collect nominations and rationales until the end of October, start the committee discussion November 1st with a vote early December. Hopefully this means the implementation makes it to 9.10.

Thanks @nomeata, this sounds good to me given the 9.10 schedule.

@dbeacham
Copy link

Is it worth having a list of all extensions annotated with which are included and nominated for GHC2021 and GHC2014 respectively? Discovery of what's missing from GHC2021 is a bit difficult otherwise.

Sorry if I've missed such a list.

All current extension in 9.6.3

@nomeata
Copy link
Contributor Author

nomeata commented Oct 11, 2023

included in GHC20201

See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/control.html#extension-GHC2021 for the official list (will add link to the proposal)

nominated for GHC2024

see the proposal https://github.com/ghc-proposals/ghc-proposals/blob/joachim/ghc2024/proposals/0000-ghc2024.rst#proposed-change-specification

@aspiwack
Copy link
Contributor

aspiwack commented Oct 12, 2023

(we need to make it possible for GHC to output the list of extensions not part of a language, figuring this out is tedious!)

  • If we're adding -XMonoLocalBinds, then there is no reason not to add -XTypeFamilies anymore. Let's!
  • I'd suggest -XDataKind too. Goes well with -XTypeFamilies and -XGADTs; it's well-tested.
  • -XDefaultSignatures I can't think of any downside.
  • Question: if we're adding -XDerivingStrategies, can we use the any strategy without adding -XDeriveAnyClass? If so, I would recommend deprecating -XDerivingAnyClass, if not, should we consider its inclusion?
  • -XTypeInType has become absolutely standard. (see the next couple of messages)

I'd also suggest, which is probably more contentious, but let's get the discussion started on this one:

  • -XImpredicativeTypes

@JakobBruenker
Copy link
Contributor

JakobBruenker commented Oct 12, 2023

-XTypeInType has become absolutely standard.

-XTypeInType is actually deprecated and now only acts as a synonym for -XPolyKinds, -XDataKinds, and -XKindSignatures (see User Guide)

@aspiwack
Copy link
Contributor

@JakobBruenker Oh, right. I'd completely forgotten about that, thanks. Well, only -XDataKinds is missing, and I was already proposing inclusion, so it's just one less line in my suggestion.

@nomeata
Copy link
Contributor Author

nomeata commented Oct 12, 2023

@aspiwack if you are feeling confident about your nomination, please edit the proposal directly, and maybe include some rationale.

@jvanbruegge
Copy link

I'd like to make a case against DefaultSignatures and DeriveAnyClass (I agree on the rest of the suggestions from @aspiwack ).
DeriveAnyClass is only useful together with DefaultSignatures and dangerous if used without, creating runtime errors (especially without -Wall).

DefaultSignatures latter is mainly used to provide an instance based on GHC.Generics. The main problem with it is that it does not compose well. The "blessed" instance needs to be added by the author of the type class and you cannot easily add other default implementations after the fact (e.g. based on another generic representation).

Given that the Generically newtype is now in base, GHC should promote using DerivingVia instead and eventually deprecate DefaultSignatures and DeriveAnyClass

@andreasabel
Copy link

Who are the folk who maintain the Hackage infrastructure?

Those are @gbaz and @davean, if I am not mistaken.

@tomjaguarpaw
Copy link
Contributor

Who are the folk who maintain the Hackage infrastructure?

Those are @gbaz and @davean, if I am not mistaken.

This is an interesting question. @gbaz and @davean are Haskell Infrastructure Admins, and that might imply they are also Hackage administrators (contact details under "Reporting Problems"). The group that determines Hackage policy might be another group entirely. I'm not sure.

@gbaz
Copy link

gbaz commented Jan 5, 2024

Hackage does not do a check for a language version existing now. In general we do not want hackage to perform any checks cabal does not. We at most want hackage to turn some cabal warnings into hackage errors -- in fact, the cabal codebase specifically is designed to warn on things that may cause hackage upload errors, and the intention is that every package that cabal check passes warning-free should be uploadable to hackage. The only additional checks hackage does, outside of some ad-hoc things that have been done at times to check things ahead of new cabal releases, have to do with tarball size, well-formedness, etc -- things that are not about the cabal file per-se.

Here's the issue where default-language was made optional by cabal: haskell/cabal#6288

There's no real motivation for it, and I think it was an unfortunate decision.

If we want to force users to specify default-langauge, then the order of operations is we should make at least a warning in cabal. I would suggest that interested parties just open a cabal ticket to make it entirely non-optional again. I see no good reason why it was made optional, and many good reasons to require it.

however, note that all cabal packages have an implicit bound on the ghc they work with, as set by their bound on base. And this in turn proxies to limiting to a range of which "default-language" options will be implicitly selected as the compiler default by the compiler versions that correspond.

So as long as changes to ghc's implicit default-language correspond to major version bumps in base, then the situation as it stands is workable.

Finally -- note that cabal init generates a file with a default-language automatically. So it is possible that there are packages on hackage with no default language, but it is likely there are very few. Somebody would need to grep the full tarball to be certain.

@phadej
Copy link
Contributor

phadej commented Jan 6, 2024

I see no good reason why it was made optional,

Because it's not a hard requirement. People complained that writing minimal .cabal file is too much work. E.g. people were very vocal about cabal install --lib not working. They wanted a global installed library environment which just works, but...

The issue is that:

  • ghci command just works,
  • but ghci with libraries doesn't just work
  • so people want a way to get a repl with libraries (on Hackage, or locally or ...) available as easily as possible.
  • so they thought they want the "old way" of just installing stuff and dealing with cabal (dependency) hell (they don't want that).

I think that writing a bare minimum .cabal file is good enough way to achieve the repl with dependencies. Creating a package description doesn't mean you need to upload it Hackage. It can be just a local build specification. Creating a package definition should be easy. Uploading to Hackage may require a bit more work.

Or to put it differently: .cabal files are not only meant to be descriptions of packages to be uploaded to Hackage.

And that means that .cabal spec will always have a design dilemma of being easy for throw away stuff, but robust for persistent stuff (e.g. for distribution, like via Hackage).

(recall auto populating exposed-modules: would be nice for quick experiments, but not a great idea for Hackage uploads)

IMHO a compromise is to allow .cabal file to not require much, and make cabal check be the strict(er) check. I admit that it was an oversight to not make cabal check warn that not specifying default-language would result in Hackage rejecting the package.


Your experience may vary, but for myself cabal init is awkward for throw away experiments: it asks too much and wrong stuff, and non-interactive way doesn't ask stuff and adds stuff to .cabal file which I don't want (It adds comments which are just annoying, and defaults to Haskell2010, where GHC2010 is better default for quick experiments). Throwing manually together a minimal .cabal file like

cabal-version: 2.0
name: foo
version: 0

library
  build-depends: base, ...
  exposed-modules: Foo

is just better user experience for myself. TBH, I have a saved code-snippet in my text editor which has a bit more stuff, but I'm not always using my text editor, so occasionally I write .cabal files manually. Also cabal init errors on packages named foo, because package of such name exists: https://hackage.haskell.org/package/foo. That annoys me a lot, as foo is my go to throw away package name.

@gbaz
Copy link

gbaz commented Jan 6, 2024

I don't agree with all the above reasoning, but I think its not worth hashing out further, especially in this ticket. We have a pretty clear plan of action that we can all agree on -- a pr to the cabal repo that creates a warning for missing language of at least "suspicious" severity -- which will lead to it being classified by isHackageDistError as something hackage would reject, and will lead to hackage, when it moves to using the new version of the cabal library, indeed rejecting the package.

@nomeata
Copy link
Contributor Author

nomeata commented Jan 6, 2024

and will lead to hackage, when it moves to using the new version of the cabal library, indeed rejecting the package.

So the authoritative place for the checks that hackage performs is in the Cabal library after all? Then my answer on the other thread wasn't missing the mark after all, phew.

@phadej
Copy link
Contributor

phadej commented Jan 6, 2024

So the authoritative place

I'd argue it's not authoritative, and shouldn't be. hackage-server can do additional checks on packages, and add them quickly, independently of Cabal (and it does, e.g. recent PackageInfo stuff). hackage-server can also ignore some warning checks issued by cabal check.

The analogy is that GHC has various warnings and has various severities for warnings (-Wdefault, -Wall, ...). And it's arguable that -Wdefault errors may cause distribution issues. But it is users (e.g. in their CI setup) who make some -Werror choices. And maybe run HLint which adds even more warnings. And in some other world, Hackage could actually build packages on upload and maybe reject some if there are some - non fatal - issues reported by GHC + other inspection tools.

But we leave in the real world unfortunately. E.g. Stackage maintainers rejected to add -Werror=missing-methods to their setup, so Stackage couldnot become missing-methods free package set, "because they track upstream". And now we are in limbo, with -Werror=missing-methods like behavior is many years away. Recall, my motivation for -Werror=missing-methods is to make change assessments easier, and if only Stackage is used as the assessment package set - we wouldn't need having -Werror=missing-methods in GHC. (And having -Werror=missing-methods in GHC2030 doesn't fulfill the motivation, 99% of Stackage is Haskell2010, and probably will be for a long time).

Now as I bring that up, I notice that I have been myself inconsistent. In Cabal I was ok to be lenient, with GHC I now want to be more strict. I think I'd be fine if it's Stackage that is cranked up strict (does actual code checks, in addition to just building code and running some tests), Hackage less so (doesn't build stuff nowadays, cannot check "everything"), and then Cabal and GHC even less so (E.g. even allowing symbols with just type signatures, but no actual binding!)

For the record: haskell/cabal#6288 no-one objected making default-language optional back then (e.g. not even Herbert who is usually quite strict about things). I can only guess and try to remember that people were annoyed by a warning that you can omit default-language, and nothing actually broke (and there weren't GHC2021 on the horizon in 2019).

@nomeata nomeata merged commit 5f9f1d5 into master Jan 9, 2024
@nomeata nomeata added Accepted The committee has decided to accept the proposal and removed Pending committee review The committee needs to evaluate the proposal and make a decision labels Jan 9, 2024
@adamgundry
Copy link
Contributor

adamgundry commented Jan 17, 2024

I've opened haskell/cabal#9620 to track the Cabal-level warning discussed above.

The fact that changing GHC's default language to GHC2024 will break existing programs (albeit only those that do not specify a language edition) has also come up in discussion on the implementation MR (https://gitlab.haskell.org/ghc/ghc/-/merge_requests/11882#note_543068). I wonder if we should have GHC emit a warning when compiling a module without an explicit language edition, to alert users that it may break in future releases? (After all, not all existing programs are Cabal packages.) Of course it's potentially a bit late to introduce the warning in 9.10 if we are also changing the default in 9.10...

@nomeata nomeata deleted the joachim/ghc2024 branch January 17, 2024 08:29
@mpickering
Copy link
Contributor

Given the discussion on this ticket, I am quite surprised that a GHC MR has been proposed already which bumps the default extension to GHC2024.

  • This causes breakage for standalone scripts (as can be seen widely in GHC's testsuite).
  • This also potentially causes breakage for packages which don't specify a default language.

It seems that these issues with the ecosystem need to be patched up first before such changes can be introduced by default.

It seems that for 9.10 it would be ok to introduce GHC2024 as an extension set but I am currently strongly opposed to making it the default.

@nomeata
Copy link
Contributor Author

nomeata commented Jan 17, 2024

It was always the explicit plan that GHC when run as-is gives you the latest edition, for a good experience in ghci and throw-away scripts, and that code that should last more than one GHC release should be explicit in the edition. This is how we did it for GHC2021 (which enabled many more extensions than GHC2024). Of course it’s something we could have communicated more loudly, but that’s always the case.

It’s a bit of unfortunate timing that cabal dropped the requirement to specify a language editions around the time we set out these rules and GHC2021 was introduced (under the assumption that Cabal requires a language to be specified), but do we have evidence that people don’t specify an edition? (I doubt it)

The use case of just firing up ghc or ghci remains a useful one, and I would not want that to warn me about lack of -XGHC2024. At least not in -Wdefault.

The GHC testsuite is hardly representative here; it tests weird corners by construction, and it is written to work with just the current GHC, with the least effort.

@mpickering
Copy link
Contributor

The environment is now very different than when GHC2021 was proposed and merged, there is clearly a focus now around stability so it is disappointing that the steering committee is quite gung-ho about introducing this breakage without waiting for suitable mitigations to exist in the ecosystem.

It seems that at least cabal developers, and also ghc developers (myself) are not aware of this expectation that everyone must provide a language edition for any stability guarantee. It seems to make other stability efforts a bit pointless if every few releases many standalone scripts will break because a new non-conservative language edition will be released and quickly made the default.

Is this change going to break people compiling xmonad configs? Will this change render instructions about using GHC directly in university courses redundant? The proposal is quiet about any kind of breakage impact and whether the ecosystem is ready to absorb such breakage, even if "it was always the plan", that doesn't mean everything is lined up and ready for the change.

@nomeata
Copy link
Contributor Author

nomeata commented Jan 17, 2024

Of course you have a point, and it’s not completely unexpected. The worry that we’ll have this “OHG GHC2024 suddenly happens what do we do why is not everything behaving the way it did since GHC2021” effect was one of the main reasons I tried to push for more frequent GHC20xx releases, so that it wouldn’t have come as a surprise anymore, no more than a GHC release itself. But I failed to convince back then.

Anyways, I will not stand in the way of a decision to make GHC2021 not the default until the world is ready, should someone make a push for that.

@alt-romes
Copy link

alt-romes commented Jan 17, 2024

I share Matthew's opinion. MonoLocalBinds, more precisely, is quite dangerous by default for non-cabal packages, because it is mostly in scripts that eg top-level definitions go by without signatures whatsoever.

Simon raised this point earlier in the thread, but it got somewhat resolved/cleared as "to upload to hackage, a default-language is mandatory". However, that fails to account for scripts and lecture-notes/material and such.

Even though GHC2021 introduced a lot of extensions, did it introduce one with as much potential for breakage as MonoLocalBinds? I think it is a fair extension to include in GHC2024, just not by default when running the compiler!

When part of a package, this is much less of a problem. First, because default-language is required for hackage and just often used in general. Second, because packages are more "robust" to MonoLocalBinds in the sense that package's don't often have top-level bindings without type annotations, even if a few local lets don't.

It's unfortunate that we seemingly overlooked this before the proposal was accepted.

And I agree with @nomeata that we shouldn't introduce a warning by default to require a language extension -- that is indeed too burdensome for a quick ghci session.

@simonpj
Copy link
Contributor

simonpj commented Jan 17, 2024

It seems that at least cabal developers, and also ghc developers (myself) are not aware of this expectation that everyone must provide a language edition for any stability guarantee

It's an absolutely key part of GHC Proposal #625, for which I have widely sought feedback. See GR1.

A standalone script specifies what compiler to use (Python, Haskell, bash etc). Think of ghc -XGHC2021 as a different compiler to ghc -XGHC2010. Every script should specify a language edition, to specify the language in which it is written. That's not true today, but I see no other way to ensure their stability.

However GR3 says that, whenever possible we should release a compiler that warns of an upcoming change, rather than simply introducing it. Sometimes it it not feasible to do this. For example adding foldl' to Prelude (a recent change) broke a lot of packages.

In the case of MonoLocalBinds I think that, with some non-trivial work, one could warn about bindings that will be rejected with MonoLocalBinds. Then we could release a compiler that warns, and make GHC2024 the default in the release after. Would that help?

@adamgundry
Copy link
Contributor

I'm not sure we need to go to the trouble of checking for issues specific to MonoLocalBinds (although it wouldn't hurt). It would seem rather easier to emit a warning if a language edition is not specified, would raise user awareness of the need to specify an edition to have a stable language, and is what we want to avoid future problems related to other extensions.

We could put the warning in -Wdefault when ghc compiles a module (including loading it into ghci), but leave it disabled by default for interactive ghci sessions. This is a compromise, but I think it's much more likely that users will still expect their modules to compile when they upgrade their compiler than they will expect their ghci sessions to behave in the same way. It will slightly bother users creating one-off modules and just firing up ghc, but one can always create a shell alias for ghc -XGHC2024...

@adamgundry
Copy link
Contributor

I've made a PR specifying the above idea: #632

hubot pushed a commit to ghc/ghc that referenced this pull request Feb 16, 2024
See ghc-proposals/ghc-proposals#613. Also
fixes #24343 and improves the documentation of language editions.

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
hubot pushed a commit to ghc/ghc that referenced this pull request Feb 20, 2024
See ghc-proposals/ghc-proposals#613. Also
fixes #24343 and improves the documentation of language editions.

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
hubot pushed a commit to ghc/ghc that referenced this pull request Feb 21, 2024
See ghc-proposals/ghc-proposals#613. Also
fixes #24343 and improves the documentation of language editions.

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Accepted The committee has decided to accept the proposal
Development

Successfully merging this pull request may close these issues.

None yet