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
base: master
Are you sure you want to change the base?
Conversation
ac60e1f
to
d529659
Compare
My biggest worry is how this will play out in the wider hackage ecosystem. I see two possible scenarios:
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 |
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 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. |
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. |
There was a problem hiding this comment.
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.
Another sidenote: we decided against |
@nomeata I think your 2 is still better than the status quo. If a bunch of people are using Right now, a reason that stability arguments are so emotionally charged is that while it is clear that:
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. |
There was a problem hiding this 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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
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 |
There was a problem hiding this comment.
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? 😅
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
~~ @phadej ~~ @michaelpj I don't think this is an alternative to #601 per-se. I see them both being useful like this:
|
@Ericson2314 you probably meant to mention someone else. |
Only if they have a choice. If the |
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.
|
@phadej [this time the right at-mention]
That's exactly right
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
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.) |
Like stripping down I'm not sure that it's possible to strip GHC Haskell to that degree. On the I'm curious how hesitant people in Rust community are when they asked to depend on some crate. I learned (through investigating |
@phadej I would be completely OK excluding all of
Same!
I still don't understand why we moved it to |
Because people didn't like to depend on |
@phadej I think the culture has changed as people have come to see the costs more. E.g. the |
That doesn't help, if every library has their own version of |
@phadej It's far better that people fail to agree on a |
In your scenario, the How the evolution would been worked, if the policy you proposing would been in place. Would be able to get I really don't feel that 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". |
That would indeed mean that Would GHC.Generics be That isn't really related to this proposal as written, as it has "breaking changes after a warning period", but I don't see |
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>
@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 |
Co-authored-by: Michael Peyton Jones <me@michaelpj.com>
@phadej regarding your comment here:
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 |
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
Hang on - I think there's something here that's not in the proposal. Is But it seems like the spirit of this proposal is that it should be transitive. That is, you need to set The alternative is that you have to do something like
which I think defeats the desire which is for 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. |
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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?
It is not. Your
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 |
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. |
@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 |
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 I don't think this is currently possible, since the GHC options can be set in extremely versatile ways. They can be set using The combination of these means that there is no easy method to determine if 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 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 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 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. |
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. |
I'm not sure we do, at least not here. I'd expect:
For moving existing features behind experimental flag, I'd expect someone to raise a GHC proposal.
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). |
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 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. |
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>
@adamgundry I'd like to submit this to the committee! |
There was a problem hiding this 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. |
There was a problem hiding this comment.
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?
@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. |
As others have said, the impact of the proposal depends greatly on whether
I feel that the proposal lacks the discussion of ecosystem impact. As things stand I must admit that I'd enable |
In that case let's haggle now, rather than having |
@angerman I wonder if you could expand the Proposed Change Specification? It currently says (in its entirety)
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 A couple of other questions
Making the spec precise will help us debate it without misunderstandings. Thanks! |
I don't think transitive makes sense. At the very least, 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. |
The word "transitive" does not appear in the proposal, so I'm confused. |
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. |
Since the question of whether |
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:
This has the benefits that:
|
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