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

Add -experimental flag #617

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

Conversation

angerman
Copy link
Contributor

@angerman angerman commented Oct 9, 2023

This proposal seeks to add an -experimental flag to GHC to cleanly delineate experimental from non-experimental features; making experimental features explicitly opt-in.

rendered

@angerman angerman self-assigned this Oct 9, 2023
@nomeata
Copy link
Contributor

nomeata commented Oct 9, 2023

My biggest worry is how this will play out in the wider hackage ecosystem. I see two possible scenarios:

  1. Library authors really refrain from using -experimental for practically every library used by others. Users can avoid using -experimental easily. Success!
  2. Library authors start uploading libraries to Hackage using -experimental features. Maybe they even label the library itself as experimental, but maybe the libraries are useful nevertheless, and other libraries and users start depending on it. User’s are forced to use -experimental.

You briefly mention this in the proposal, but it would like to see more reassurance that 2 will not happen (because if it will, this would have been introducing more bureaucracy for little gain).

For example: Should hackage have a policy of not even allowing packages that set -experimental in their ghc-options (or else forbid experimental features), so that commonly available libraries are always compatible with -no-experimental? Or is that too strict (e.g. where would an experimental LinearTypes ecosystem be hosted? Just on github?)?

@hasufell
Copy link

hasufell commented Oct 9, 2023

You briefly mention this in the proposal, but it would like to see more reassurance that 2 will not happen (because if it will, this would have been introducing more bureaucracy for little gain).

That's a fair point. But the way I see it is that hackage should have a prominent feature that displays whether a package does in fact depend on experimental (either on module level or in the .cabal file).

I myself certainly would prefer using a library that does not use experimental features: but how does the normal end user figure this out? They probably don't want to download the package and grep through it.

This needs to be more prominent. The question is whether that's in scope for this proposal.

CCing @Kleidukos who may have an opinion on the hackage side.

Comment on lines +144 to +146
2. **Separate GHC Builds**: Provide separate GHC builds for experimental
features. This ensures a clear separation but might be cumbersome for
developers to manage multiple GHC installations.
Copy link

@hasufell hasufell Oct 9, 2023

Choose a reason for hiding this comment

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

Sidenote: I've been wanting to write a proposal for this. But after talking to @simonpj about this briefly, I believe it would require much more research (e.g. how does rust team deal with this), work, convincing etc.

The -experimental proposal seems more realistic to be accepted and implemented.

@hasufell
Copy link

hasufell commented Oct 9, 2023

Another sidenote: we decided against --std=experimental as a cli naming scheme, since it is somewhat of a lie: "experimental" is not a standard, unlike Haskell2010 and we want to reserve the design and implementation of a --std=... switch for a future proposal.

@Ericson2314
Copy link
Contributor

@nomeata I think your 2 is still better than the status quo. If a bunch of people are using -experimental and complaining about GHC stability, then it is clear that they are hypocrites :D. More seriously, if a bunch of people find that they (think that they) need to use unstable stuff, then this can be used to guide the prioritization of unstable features to clean up and stabilize.

Right now, a reason that stability arguments are so emotionally charged is that while it is clear that:

  1. Parts of GHC I are intentional behavior and meant to be stable

  2. Parts of GHC are dusty old experiments, emergent behavior, outright easter eggs, and not meant to stable.

There is no boundary between them. Putting up a strong division will clarify this for everyone and put some guardrails on the conversation, and that will lower the temperature in the room.

Copy link

@michaelpj michaelpj left a comment

Choose a reason for hiding this comment

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

I'm still confused about how this is better than #601

This proposal seems very similar to that proposal, but with -Werror=Unstable enabled by default and without the ability to do fine-grained warnings.

breaking changes without prior warning at any time. Non-experimental (stable)
features on the other hand would need to follow a change evolution/deprecation
process and could only under exceptional circumstances introduce breaking
changes.

Choose a reason for hiding this comment

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

This seems to bury the lede! The proposal says it is about adding a new flag, but in fact it is about instituting a much more stringent change process for a large fraction of GHC development work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This flag gives us a binary distinction between what is experimental and what is not. The exact process of lifecycle would be governed by e.g. #601 or similar proposals.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After writing the other comments further down. Let me stress that this explicitly permits to have experimental features in the compiler that can (and are permitted to) undergo rapid evolution with breaking changes at any point.

--------------------------
For maintainers there will be a ``__GHC_EXPERIMENTAL__`` macro to use with ``CPP``
to allow for conditional compilation if ``-experimental`` is active. This can
be used with the usual version macros to tailor to specific GHC versions as needed.

Choose a reason for hiding this comment

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

What would you use this for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let's assume you want to try some experimental feature but make it opt-in. You could have a flag in your cabal file -fwith-experimental, that then switches on ghc-options: -experimental, and you can CPP guard the experimental use in your module being a CPP guard.

Copy link

Choose a reason for hiding this comment

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

If you have a flag then you can simply pass your own CPP defines, so I don't see there being a reason for having this hard coded into the compiler. The only situation where you might need this is if you don't define a flag and expect users to add ghc-options in their cabal.project file but that doesn't seem like an idiomatic way to do this.

I seriously doubt as well that users will even do the flag approach as most of our tooling doesn't support optional features of packages. It would be better to just have two packages one that is experimental and one that isn't.

Choose a reason for hiding this comment

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

Indeed you're not supposed to change API surface based on flags or CPPs. But that's not what the proposal implies.

proposals/0000-std-experimental.rst Outdated Show resolved Hide resolved
proposals/0000-std-experimental.rst Outdated Show resolved Hide resolved
The introduction of this flag is expected to have minimal impact on existing
code. The initial set of features behind the ``-experimental`` flag will be
the emtpy set. Follow up proposals will be required to move existing features
behind the `-experimental` flag. New features should by default be behind

Choose a reason for hiding this comment

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

Isn't moving a feature behind -experimental a breaking change? 😅

Copy link
Contributor

Choose a reason for hiding this comment

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

The beauty of the proposal is that stable part is not actually stable. it just won't change without a deprecation period. So we can still argue on how long something needs to be deprecated before moved to -experimental. And then we can argue whether the feature (after seeing no changes being moved to or initially implemented in -experimental) is stable! /s

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Despite @phadej /s, yes, you'd be deprecating existing experimental features into -experimental. Tell people what's going to happen and then make it happen.

For extensions there is #601 which aims to describe a lifecycle. This would cover features as well. But most importantly, I think what is in -experimental and not in -experimental, should primarily be governed by how we treat it. You can't make breaking changes without an change evolution in -no-experimental parts of the compiler, while you can do that pretty freely with -experimental features and extensions.

@Ericson2314
Copy link
Contributor

Ericson2314 commented Oct 9, 2023

~~ @phadej ~~ @michaelpj I don't think this is an alternative to #601 per-se. I see them both being useful like this:

  1. -no-experimental is the constitution. Other "laws" (like Extension lifecycle framework proposal (under review) #601) are in accordance with the constitution.

  2. Language extensions do not cover all functionality. -experimental can also cover other things like CLI flags, direct access to ghc-internals, ghc-experimental, backpack, etc. In general any project will have a long tail of observable behavior that doesn't neatly fall into preconceived categories, and we still need to decide what our stability policies for it are.

  3. We still need to figure out which language features go on which side of the -experimental divide, Extension lifecycle framework proposal (under review) #601 lays the ground work for that. Or perhaps if this is accepted first, Extension lifecycle framework proposal (under review) #601 can just include the final categorization of existing language extensions too.

  4. Extension lifecycle framework proposal (under review) #601 includes guidance for deprecations the other half of the feature lifecycle and dual to experimental. ("experimental" is youth, "deprecated" is old age).

@phadej
Copy link
Contributor

phadej commented Oct 9, 2023

@Ericson2314 you probably meant to mention someone else.

@nomeata
Copy link
Contributor

nomeata commented Oct 9, 2023

@nomeata I think your 2 is still better than the status quo. If a bunch of people are using -experimental and complaining about GHC stability, then it is clear that they are hypocrites :D

Only if they have a choice. If the onlyViableJsonLibrary requires -experimental, then as a user of a Haskell app that talks JSON I have to enable -experimental to get stuff done, and nothing is gained. (It’s probably not the onlyViableJsonLibrary author who will complain, so no hypocrites around, just poor users stuck between a rock and a hard place.)

@phadej
Copy link
Contributor

phadej commented Oct 9, 2023

I remember seeing tweets where Rust library writers were happy that some feature finally made it into stable Rust (process not being particularly swift AFAIU - for a reason) so they can use the needed feature in their libs, while still using only stable Rust.

Amendment: also I understood that Rust people are a lot more aggressive dropping old compiler support, as new stable rust promises to not breaking old code: upgrading stable compiler is safe. There is a value in using stable Rust only. (Stable GHC won't give the same guarantee). Note: except when epoch happens - and new epoch haven't ever happened yet - so we don't know how it will go.

-experimental will bring new tensions and reasons to complain for sure.

@Ericson2314
Copy link
Contributor

Ericson2314 commented Oct 9, 2023

@phadej [this time the right at-mention]

I remember seeing tweets where Rust library writers were happy that some feature finally made it into stable Rust (process not being particularly swift AFAIU - for a reason) so they can use the needed feature in their libs, while still using only stable Rust.

Amendment: also I understood that Rust people are a lot more aggressive dropping old compiler support, as new stable rust promises to not breaking old code: upgrading stable compiler is safe. There is a value in using stable Rust only.

That's exactly right

Note: except when epoch happens - and new epoch haven't ever happened yet > - so we don't know how it will go.

Per https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md I think "epoch" became" edition. Editions do exist, and are so far relatively superficial like our GHCXXXX (except they are not defined as collections of underlying extensions).

(Stable GHC won't give the same guarantee).

Ya that's the big fight we need to have. And I must say I don't see why not. if we start with a sufficiently ratchet-down notion of stable Haskell, we should be able to offer just as robust a guarantee. The whole point of this proposal is to draw the line such that we can raise our standards.

(I personally am happy to use experimental stuff and have a more difficult upgrade path; just like with the Rust code I've written. But this should be a choice, not forced upon everyone.)

@phadej
Copy link
Contributor

phadej commented Oct 9, 2023

if we start with a sufficiently ratchet-down notion of stable Haskell

Like stripping down template-haskell to using just a Tree Token representation: https://doc.rust-lang.org/beta/proc_macro/enum.TokenTree.html - a completely different representation chosen so language can be evolved without breaking the interface.

I'm not sure that it's possible to strip GHC Haskell to that degree. On the base library side it would mean having a lot of stuff out, though I'd actually welcome that, but then how one would make people use Bifunctor (define instances) if it's not in base?

I'm curious how hesitant people in Rust community are when they asked to depend on some crate. I learned (through investigating hashable future) that people complain (in "meme sense", i.e. not really) that Rust is slow but that's because they use HashMap (also when an array would do) with default hash (which is apparently SipHash atm, which isn't particularly fast when you try to push the performance). And there are other options. Do people use other "small" utility crates?, e.g. something of the size of data-fix?

@Ericson2314
Copy link
Contributor

@phadej I would be completely OK excluding all of template-haskell from the initial definition of -no-experimental.

though I'd actually welcome that

Same!

but then how one would make people use Bifunctor (define instances) if it's not in base?

I still don't understand why we moved it to base. Seems to cause more problems than benefits. Anyways I hope ghc-internals vs base can allow us to have some sneaky tricks to get around this.

@phadej
Copy link
Contributor

phadej commented Oct 9, 2023

Seems to cause more problems than benefits.

Because people didn't like to depend on bifunctors package. See also the recent discussion about adding Fix to base. That's why I ask, are Rust people more open to adding new dependencies, or do they also try to make their crates with std as the only dependency. (I'd imagine they prefer the std only, as the std crate is the only one which doesn't break stuff, "have major versions", AFAIU - so if you can do your thing with std only, it's a lot less future maintenance work).

@Ericson2314
Copy link
Contributor

@phadej I think the culture has changed as people have come to see the costs more. E.g. the Fix change was not received so positively. People can make a batteries-included standard library on top of things that ship with the compiler all they want.

@phadej
Copy link
Contributor

phadej commented Oct 9, 2023

People can make a batteries-included standard library on top of things that ship with the compiler all they want.

That doesn't help, if every library has their own version of newtype Fix though, i.e. the library writing part of the community doesn't somehow converge to use common libraries. So far, AFAICT, having stuff bundled with GHC is the only way to make some people use that stuff.

@Ericson2314
Copy link
Contributor

Ericson2314 commented Oct 9, 2023

@phadej It's far better that people fail to agree on a Fix than we have a ton of breaking changes because stuff is needlessly versioned in lockstop with GHC.

@phadej
Copy link
Contributor

phadej commented Oct 9, 2023

than we have a ton of breaking changes because stuff is needlessly versioned with GHC.

data-fix haven't seen breaking changes in three years. The Fix in fact, is quite stable. And also was Bifunctor, until someone came up with an idea of adding QuantifiedConstraints to the GHC.

In your scenario, the QuantifiedConstraints would still probably be experimental feature? So if -experimental would extend to the other libraries, say also transformers, then the MonadTrans won't be able to have forall m. Monad m => Monad (t m) superconstraint, or be forced to be -no-experimental library? (No need to involve onlyViableJsonLibrary).

How the evolution would been worked, if the policy you proposing would been in place. Would be able to get QuantifiedConstraints into GHC, and transformers eventually use it, while staying in -no-experimental i.e. stable GHC subset?


I really don't feel that QuantifiedConstraints is experimental anymore. And the Rust epoch/editions is about this kind of case, where a new stable feature has arrived, and the libraries probably should be changed to use the new feature, but that is a breaking change.

But as you said, rust editions have been so far relatively superficial, so there is no data point on how it works "in the real situation".

@phadej
Copy link
Contributor

phadej commented Oct 9, 2023

I would be completely OK excluding all of template-haskell from the initial definition of -no-experimental.

That would indeed mean that onlyViableJsonLibrary will probably be forced to use -experimental, or split out the TH functionality into onlyViableJsonLibrary-th... and so will be forced the other libraries providing TH based derivation. That would be a maintenance burden.

Would GHC.Generics be -no-experimental. They do use TypeFamilies, are those experimental? Based on #601 (comment) @angerman would say they are stable, but that is conflicting with @Ericson2314's "if we start with a sufficiently ratchet-down notion of stable Haskell,"

That isn't really related to this proposal as written, as it has "breaking changes after a warning period", but I don't see -no-experimental GHC shrinking down to actually very stable (no breaking changes for very long periods of time) but still widely usable (as used on Hackage or/and in the industry) subset.

@Kleidukos
Copy link

CCing @Kleidukos who may have an opinion on the hackage side.

I wish to hear an experience report from Rust community members, as they have a similar flag (nightly) and thus an ecosystem that we're going to either imitate or learn from.

Co-authored-by: Michael Peyton Jones <me@michaelpj.com>
@angerman
Copy link
Contributor Author

angerman commented Oct 9, 2023

@phadej I disagree with @Ericson2314 on starting with a set of experimental extensions. The initial set is empty. My view has been, and will continue to be that anything that's shipped with a stable compiler release by extension has to be considered morally stable. If we start with -no-experimental being the default, we can not have breaking changes by all of a sudden precluding existing features people used in code behind a flag. If we start with a large set and -experimental being the default, this has little value.

Co-authored-by: Michael Peyton Jones <me@michaelpj.com>
@angerman
Copy link
Contributor Author

angerman commented Oct 9, 2023

@phadej regarding your comment here:

That isn't really related to this proposal as written, as it has "breaking changes after a warning period", but I don't see -no-experimental GHC shrinking down to actually very stable (no breaking changes for very long periods of time) but still widely usable (as used on Hackage or/and in the industry) subset.

My sincere hope is that for new featues and extensions that are subject to rapid change, and for which the authors want to make no stability guarantee (and we have such features, but the note is in the User Guide only), they would be guarded by -experimental from the get-go. I fully agree that moving existing features behind -experimental will be tricky. There are others who work on classifications of what should be considered experimental and what not, and we have no intention of duplicating that work.

@michaelpj
Copy link

I don't think this is an alternative to #601 per-se. I see them both being useful like this

It seems to me that this and #601 both provide a flag F that bans experimental language extensions, which we can also choose to make the default. In this case it's -no-experimental, in #601 it's -Werror=Unstable.

Only if they have a choice. If the onlyViableJsonLibrary requires -experimental, then as a user of a Haskell app that talks JSON I have to enable -experimental to get stuff done, and nothing is gained

Hang on - I think there's something here that's not in the proposal.

Is -experimental transitive? Normally, GHC flags apply to the compilation that they're used on, and that's it. In that case it would be no problem at all for onlyViableJsonLibrary to set ghc-options: -experimental but for your library X to depend on it and not set -experimental. After all, by the time it gets to building X, onlyViableJsonLibrary is just some compiled interface and object files.

But it seems like the spirit of this proposal is that it should be transitive. That is, you need to set -experimental to load a library that has been built with -experimental. Which would I guess require putting something in the interface files, like Safe Haskell.

The alternative is that you have to do something like

package *
   ghc-options: -no-experimental

which I think defeats the desire which is for -no-experimental to be the easy default. This would similarly be a problem with my suggestion of making -Werror=Unstable the default: packages could turn it off locally and it would be annoying to assert that they don't. So that's a substantive difference.

EDIT: oh, it is in the proposal, but only in an example! It should be called out, I think.

-- With -no-experimental
ghc -experimental -no-experimental Main.hs -- This will throw an error if Feature X is used

ghc -no-experimental Main.hs -package foo -- This will throw an error if Feature X is used anywhere in Main.hs or the package foo.

Choose a reason for hiding this comment

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

This implies a feature that's not listed in the change specification: that -experimental is transitive. That means in particular that we're going to have to record something about usage of -experimental in interface files, like Safe Haskell. Doable, but certainly worth calling out explicitly!

Copy link
Contributor

Choose a reason for hiding this comment

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

@angerman Are you planning to address this comment from @michaelpj?

The Proposed Change Specification is currently very brief. I think we need a lot more detail about the semantics of the flag: how does it relate to -package (and what is the impact of that design on Cabal packages)? Can it be overridden in an OPTIONS_GHC pragma?

@hasufell
Copy link

Is -experimental transitive?

It is not. Your cabal.project example is precisely how we envision enforcing this.

This would similarly be a problem with my suggestion of making -Werror=Unstable the default: packages could turn it off locally and it would be annoying to assert that they don't.

This works fine, because there's a natural order of how flags are applied. This order needs to be better documented (and regression tested).

This is the normal design most cli apps follow. You can ultimately force all your dependencies to be built without experimental features if you wish. Cabal packages can only define it in their cabal file and cabal.project and cli switch overwrite those.

@jappeace
Copy link

I think this is a step in the right direction, we can then later add other stuff behind experimental (such as linear types for example) through the normal proposal process.
I'm not reading this text as everything in GHC right now is stable.

@angerman
Copy link
Contributor Author

I'm not reading this text as everything in GHC right now is stable.

@jappeace we have to start somewhere, and part of this proposal is not to break existing code. As such, we can't start with a non-empty -experimental set. But I agree that subsequent proposals could move LinearTypes, DependentHaskell, and the items marked as EXPERIMENTAL in the user-guide behind that flag. Though those should be separate proposals, and have clear impact assessments.

@TeofilC
Copy link

TeofilC commented Oct 22, 2023

I think something like this would be a great way to make stability guarantees clearer!

I think a key aspect of this proposal is that it isn't merely a GHC flag. I imagine we'd like to see this integrated into existing tooling such as hackage-server, haddock, cabal-install, stack, etc, as has been touched on in the conversation already. I think it would be nice to see this aspect sketched out as it may have a bearing on the design of the GHC flag.

For instance I think we'd want to uphold the principle that it should be possible to easily determine whether a package uses -experimental by inspecting a source distribution (ie, without compiling the package against a specific GHC, a specific set of cabal flags, and specific sets of dependencies).

I don't think this is currently possible, since the GHC options can be set in extremely versatile ways. They can be set using OPTIONS_GHC pragmas in source files, which can be guarded by arbitrarily complex CPP. They can be set in .cabal files again guarded behind arbitrarily complex conditionals. And they can be set in cabal.project files.

The combination of these means that there is no easy method to determine if -experimental is passed to some module in a particular package without compiling it. This makes it difficult for non-GHC tooling to access this information, and it can make it complex/confusing for end users to know if they depend on an -experimental package. For instance, you might believe that your entire dependency graph is -non-experimental but perhaps if the solver had picked some different versions of some dependencies, then CPP would have enabled the -experimental flag in a different dependency.

My suggestion is that we should remove a lot of this versatility. I think the only place it should be possible to set this flag is by adding a field to a component in a .cabal file and we should guarantee that this field can never appear in a conditional. Then it becomes trivial to check if a component uses -experimental, simply parse the .cabal file and check if the relevant field is there.

I think it's good to think of this in terms of a split between an interface and a warning/error. You want to define an interface in the .cabal file that specifies whether a package is experimental or not, and then you want a warning/error from the solver/compiler if that interface is violated.

Another challenge that I forsee for something like this is that we already have means to specify the "stability" of a package or of a module's interface by setting a field in a .cabal file or adding some Haddocks to a module. Of course this is a completely different concept, but I think we will have to think about how we can minimise confusion between these two notions of stability.

I think something like this as well would have to be integrated into cabal-install solver as well, since otherwise you could very easily get into a situation where the solver gives you a build plan that can never be built, eg, the build plan chooses lib-1 which is experimental but it could have picked lib-2 which is not experimental. While it would technically be possible to workaround this as a user, the DX wouldn't be particularly nice.

@adamgundry
Copy link
Contributor

It (still) seems to me that before we discuss the details of a machine-checked mechanism for guarding experimental GHC features, we first need to reach consensus on the broader policy questions (e.g. what kinds of stability guarantees are offered and for which features, and who pays the costs of stability). Then we need to address how this interacts with library changes, which are in practice a major issue preventing upgrading to newer compiler versions early.

@hasufell
Copy link

we first need to reach consensus on the broader policy questions

I'm not sure we do, at least not here.

I'd expect:

  • GHC SC to decide on the question of how experimental something is when accepting a GHC proposal
  • CLC deciding the same for base

For moving existing features behind experimental flag, I'd expect someone to raise a GHC proposal.

Then we need to address how this interacts with library changes, which are in practice a major issue preventing upgrading to newer compiler versions early.

That seems rather orthogonal, unless I misunderstood something. This proposal is only one step to improving the broader issue of compiler upgrades. Boot/core libraries are a separate issue and out of scope (and not solvable through a GHC proposal anyway).

@angerman
Copy link
Contributor Author

This proposal explicitly does not try to come up with machine-checked mechanisms. It is primarily concerned about visibility. It also does not try to put any current feature behind the -experimental flag, and puts that purposefully up for subsequent proposals.

While it does say that features not behind -experimental, ought to follow a proper change migration, and this is already implicitly followed by the SC and CLC, there will be a separate proposal for a stability policy.

The primary goal of this proposal is still to give us metadata in the compiler about what is supposed to be experimental. As outlined in the proposal, this is currently very soft defined only in the user guide where items as marked EXPERIMENTAL. A subsequent proposal, will propose moving those items behind -experimental, as the intention of them is clearly to be experimental. Any further features being behind -experimental again, would go through he proposal process.

The upside is that the compiler could tell that you use an experimental feature, or in the case where the compiler might suggest you use a feature, not suggest you to use an experimental feature, or at least warn you about the feature it's suggesting being experimental.

The primary interface for many of us to haskell is the compiler, and the compiler should know what is considered experimental or not. Currently it does not.

This proposal aims to equip us with the ability to inform about this only. If the compiler knows what's experimental, it can do so very light mechanical checks. Anything more fancy is out of the scope of this proposal.

proposals/0000-std-experimental.rst Outdated Show resolved Hide resolved
proposals/0000-std-experimental.rst Outdated Show resolved Hide resolved
proposals/0000-std-experimental.rst Outdated Show resolved Hide resolved
angerman and others added 3 commits January 25, 2024 16:03
Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>
Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>
Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>
@angerman
Copy link
Contributor Author

@adamgundry I'd like to submit this to the committee!

@adamgundry adamgundry assigned simonmar and unassigned angerman Jan 25, 2024
@adamgundry adamgundry added the Pending shepherd recommendation The shepherd needs to evaluate the proposal and make a recommendataion label Jan 25, 2024
Copy link
Contributor

@adamgundry adamgundry left a comment

Choose a reason for hiding this comment

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

I remain somewhat unconvinced that this proposal pays its way.

The de facto situation is that we have quite a few clearly experimental features (e.g. OverloadedRecordUpdate), and other features that are somewhere in between experimental and stable. I agree it would be better to more clearly identify these features. But if we start with the -experimental set being empty, we misleadingly claim that those features are not experimental. And if we start with it non-empty, we cause churn for users who have already opted in to the features (e.g. via LANGUAGE pragmas).

-- With -no-experimental
ghc -experimental -no-experimental Main.hs -- This will throw an error if Feature X is used

ghc -no-experimental Main.hs -package foo -- This will throw an error if Feature X is used anywhere in Main.hs or the package foo.
Copy link
Contributor

Choose a reason for hiding this comment

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

@angerman Are you planning to address this comment from @michaelpj?

The Proposed Change Specification is currently very brief. I think we need a lot more detail about the semantics of the flag: how does it relate to -package (and what is the impact of that design on Cabal packages)? Can it be overridden in an OPTIONS_GHC pragma?

@Ericson2314
Copy link
Contributor

Ericson2314 commented Jan 26, 2024

@adamgundry I would say the haggling over where to draw the boundary is very much ought to be part of the purpose of this proposal.

I expect that to be messy, but also a crucial step in ending the acrimony over this stuff. Some people will be upset that some shoddy half-baked thing that has lived for a long time will be marked stable. Other people will be upset some other shoddy half-baked thing that has lived for a long time will be marked unstable. But at least we'll all know what the agreement is.

Right now, the community is in "agree to disagree" mode, and you have to be an insider to know what parts of GHC are trustworthy, and what parts are old baggage. That is not a good state of affairs.

@Bodigrim
Copy link

Bodigrim commented Jan 27, 2024

As others have said, the impact of the proposal depends greatly on whether -experimental is enforced transitively or not.

  • If it's not transitive and the flag impacts only a current package, it's largely OK. We can display a shiny Hackage badge for such good citizens, but that's it.

  • If it is transitive then user experience is likely to follow in the footsteps of Safe Haskell. Which is not great to start with (because of dreaded Safe-Inferred and unresolved PVP questions), but this time without an escape hatch of Trustworthy.

I feel that the proposal lacks the discussion of ecosystem impact. As things stand I must admit that I'd enable -experimental in bytestring or text as soon as a burning need arises, zero thoughts given. Moreover, if the semantics is transitive, I'm likely to put it there upfront just not to nurture false expectations and get yelled at by downstream maintainers later. Would I be discouraged to do so? Would GHC policy prohibit such antics for boot libraries?

@adamgundry
Copy link
Contributor

I would say the haggling over where to draw the boundary is very much ought to be part of the purpose of this proposal.

In that case let's haggle now, rather than having -experimental control the empty set of features. 😁 In the interests of keeping this thread for discussion of this proposal as it stands, I've started a discussion at #635.

@simonpj
Copy link
Contributor

simonpj commented Jan 27, 2024

@angerman I wonder if you could expand the Proposed Change Specification? It currently says (in its entirety)

  • Introduce a new compiler flag -experimental.
  • Introduce a new compiler flag -no-experimental (default).
  • Features not behind the -experimental flag will have to adhere to a deprecation cycle before introducing breaking changes.

-experimental is a superset, therefore -experimental could depend on code without -experimental. The inverse does not hold.

Semantically the last -[no-]experimental flag passed to GHC will win.

That says we will have a flag, but doesn't say what it does. You may think that is obvious, but I am not sure.

For example it could be a warning -Wexperimental, which warns if any experimental feature is used. It could be made an error by -Werrror=experimental. That could be the default, if desired. But it'd fit within the warning-flag world rather than being a new kind of thing. Or maybe you had some special behaviour in mind.

A couple of other questions

  • Can it be switched off in a particular module {-# OPTIONS_GHC -experimental #-}?
  • If it's on by default this would be a breaking change -- many packages will fail. Is that your intent?

Making the spec precise will help us debate it without misunderstandings. Thanks!

@Ericson2314
Copy link
Contributor

Ericson2314 commented Jan 29, 2024

I don't think transitive makes sense. At the very least, ghc-internal will use experimental/unstable things, and yet base presents a very stable interface and depend upon it.

It is possible people will want to audit the non-transitive exceptions (audit when stable depends on unstable), but that can be atop a non-transitive foundation.

@simonpj
Copy link
Contributor

simonpj commented Jan 29, 2024

I don't think transitive makes sense

The word "transitive" does not appear in the proposal, so I'm confused.

@michaelpj
Copy link

If you want this to be like Rust, or like "having a different compiler", then I think you need it to be transitive. Note that this is somewhat divisive in Rust-land; with many people feeling like they are "forced" into using the Nightly toolchain because key dependencies require it.

@tomjaguarpaw
Copy link
Contributor

The word "transitive" does not appear in the proposal, so I'm confused.

Since the question of whether -experimental is transitive has been the subject of much discussion here, and I don't yet see the question resolved, it probably should appear explicitly in the proposal, for clarity.

@hasufell
Copy link

Not trying to step on @angerman's toes, because he's the champion of this proposal, but I agree that the proposal needs a bit more hashing out.

My gut feeling is that the following constellation would get this proposal more support:

  • -experimental is the default for now
  • there's no transitivity... if you want -no-experimental to apply for all dependencies, use cabal.project (or similar), which allows to do that easily
  • re classification: rather start with a large set of experimental extensions (as in: err on the side of experimental). Then gradually move things to stable.

This has the benefits that:

  1. it doesn't conflict with the stability goals (no breaking change, opt-in)
  2. it doesn't allow ecosystem effects to creep into our judgement ("but most of hackage uses extension XY, we can't mark it experimental")
  3. it encodes the status quo (pretty much everything is experimental and enabled by default) and allows us to gradually move away from it => creating incentive to stabilize extensions

@simonmar
Copy link

@angerman there are some questions above regarding the transitivity of -experimental and asking for clarification on some points (from @simonpj), I'll put the proposal back in needs-revision pending those.

@simonmar simonmar added Needs revision The proposal needs changes in response to shepherd or committee review feedback and removed Pending shepherd recommendation The shepherd needs to evaluate the proposal and make a recommendataion labels Mar 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