-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
The 1.18 release of the Go language is likely to include by far the biggest change to the language since its creation: parametric polymorphism, colloquially called generics. There has been much discussion about how the core libraries will adapt, and how to make that adaptation. See #45955 and #48594 for example, and there are others already and sure to be more soon.
How to use these ideas in the standard library requires great thought and planning. Putting them in the library now also adds a significant burden to rolling out the release.
I propose that we do not update the libraries in 1.18.
The reason is simple and compelling: It's too much to do all at once, and we might get it wrong. The language changes have been worked on in some form for over a decade, but the library changes are very new, and we have no experience with the use of the new types in Go on which to base a strong case for their design. Yes, we can reason about them at length and much has been done. Experience with other languages helps, but one thing Go has taught us is that it grows its own ways of doing things.
For generics, we don't know what those new ways are yet. Also, the compatibility promise makes the cost of getting any detail wrong quite high. We should wait, watch, and learn.
Instead, I propose we still design, build, test, and use new libraries for slices, maps, channels, and so on, but start by putting them in the golang/x/exp repository. That way, these new libraries - which are truly experimental at this stage - can be tested in production, but can be changed, adapted, and grown for a cycle or two, letting the whole community try them out, if they are interested and willing to accept a little instability, without requiring every detail of every component to be ready from day one. Once they have soaked a bit, and updated through experience, we move them into the main repo as we have done with other externally-grown packages, but with the confidence that they work well in practice and are deserving of our compatibility promise.
I realize everyone wants to get their hands on the fun of the new language feature, and is looking forward to fixing some of the issues in the core libraries that will be less clumsy once it arrives, but I strongly believe it is best to take it slow for now. Use, learn, study, and move cautiously.
Activity
ALTree commentedon Oct 12, 2021
Agree. For example, it looked like we were going to add a few new things like
constraints.Slice
andconstraints.Map
, which I found really ugly (but thought were necessary), but now after #48424 it looks like they may be not needed (See #48424 (comment)), which is great! And this happened last week (#48424 was accepted 5 days ago).To me this suggests we don't yet fully understand how the current generics implementation (and possible refinements that may be implemented in the near future) would influence the design of these new libraries; so it may be premature to commit to an API for them. Putting them in
x/exp
seems like a prudent move.earthboundkid commentedon Oct 12, 2021
The slices package has been whittled down to a very functional core. For example, it has no Map or Filter because those werenβt obviously useful. I think itβs good to ship as is. Dropping it now just adds delay for no real reason.
Similarly, if constraints isnβt part of 1.18, there will be a lot of independent redefinitions of orderable types. I donβt think weβre going to learn from experience much that could change that package now.
I agree though that container/set can wait for another cycle (iteration is still up in the air), and probably many or all other changes.
mvdan commentedon Oct 12, 2021
This reminds me of the transition done to error values via https://golang.org/x/xerrors, which I think worked really well.
Just one question: would these x packages allow backwards incompatible changes? If so, I think putting in
x/exp
and clearly documenting them as such would be fine. If they'll follow backwards compatibility guarantees, much likex/xerrors
did, then perhaps I'd place them under a new module such asx/generics
orx/typeparams
.I'd personally lean towards a new module with backwards compatibility guarantees. Otherwise, it would be risky for Go modules to start using and relying on them, as they may break at any moment. Especially when it comes to libraries, as they can't "pin" a specific version due to MVS. If we learn from past mistakes and want to remove or redesign APIs, we should simply deprecate, and do the backwards incompatible changes in bulk when moving the APIs to the standard library.
jaloren commentedon Oct 12, 2021
I concur with this proposal. More concretely, I doubt we should be adding generic libraries or updating existing ones until we have an answer to #48287. And getting an answer to that discussion likely requires time and experimentation from the community .
The one exception may be the constraints library, which strike me as an essential part of the generics design and would severely degrade developer ergonomics without it.
Having x/generics module with backwards compat guarantees sounds like an excellent idea.
mvdan commentedon Oct 12, 2021
Another advantage of an external module is that, if a proposed new API gets accepted and implemented, users on Go 1.18 or later can start relying on it the moment it hits the master branch, instead of waiting 3+ months until the next Go release is out with its standard library changes.
andig commentedon Oct 12, 2021
I understood rob doesn't want to change the existing libraries. It seems a good idea to introduce new ones and potentially NOT promise to keep them or their api for one or two releases. That will gain more real-world feedback.
thepudds commentedon Oct 12, 2021
Minor: that proposal is in "likely accept", and not yet accepted, though there is a prototype.
Separately, if the new packages do start at
x/β¦
(x/generics
,or something else), hopefully they could be tagged to clearly communicate to tools and to humans any backwards compatibility intentions that apply at that import path location (e.g., perhaps something like v0.1.0 ~soon, and v1.0.0 when go1.18 is released, with an option to move to v2 at thex/exp
x/β¦
location if warranted, which helps with library importers and so on).When those capabilities land in the standard library, or if there is a v1 to v2 change at
x/β¦
, ideally migration for clients could be handled via cmd/goβs hopefully-not-too-distant automatic API migration (initially described here and more recently discussed here).EDIT: FWIW, I think everything I wrote above is cleaner if the repo is not
x/exp
, but instead new separatex/something
repo(s).doggedOwl commentedon Oct 12, 2021
Why does it have to be a blanket decision? There are some proposed changes that might need some more work and for those it's reasonable to be in x/* but IMO there are some proposals like the slices package who are reasonably well defined and would be very helpful to have since the start.
mvdan commentedon Oct 12, 2021
@doggedOwl one way to look at it is that Go 1.18 is already a huge release, with generics in the language and fuzzing support. And drawing the line around what generic APIs are fully ready to be frozen is hard, especially when we have had close to no experience with them being used in the wild.
bitfield commentedon Oct 12, 2021
I made the following comment on #45955, which I think supports Rob's point:
Unfortunately, responders to that issue were not able, or not willing, to supply any such programs (so far as I'm aware). I think the best way to get them is to put something in the
x
tree, as suggested, and let people use it for a while.The kind of programs I'm talking about are not merely examples cooked up to demonstrate how a certain feature would work. They are demonstrations that such a feature is necessary, widely useful, and worth the cost in additional complexityβa quality bar that has traditionally applied to all Go proposals, not just this one. I see no reason it shouldn't apply here.
Not to labour the point, but it's always surprising to me how long and carefully I can think about some design a priori, and then the moment I actually try to use it, I find it's instantly obvious that I've designed the wrong thing. That's not just me being dumb (though of course that's a factor): it's simply inevitable.
Releasing a draft API in 'experimental' mode is exactly the right thing to do here. When it becomes clear to us all that that API needs to change in several important respects (I'm happy to put money on this outcome if anyone seriously doubts it), it will still be possible to make those changes. The moment it goes into the standard library, that door is closed forever.
Measure twice, cut once.
ianlancetaylor commentedon Oct 12, 2021
@carlmjohnson I agree that container/set should not go into 1.18. I just edited the discussion (#47331) to say as much.
I am also inclined to say that we should not add type parameters to any existing standard library packages for 1.18, especially given #48287.
But I do personally think that we need the constraints package at least in 1.18. Many uses of type parameters are going to need the constraints package. I see no advantage to using an x repo for constraints, which will force us to retain a pair of packages for some time going forward.
So I think that for 1.18 this proposal is really about the slices and maps packages. Just my own opinion, of course.
neild commentedon Oct 12, 2021
Putting the proposed Go 1.13 error changes in
golang.org/x/exp/xerrors
was very useful for validating the API before committing to it.However, applying the compatibility guarantee to the
x/exp
package made it impossible to iterate on the API. The eventual changes to theerrors
package in Go 1.13 differed from thexerrors
prototype in various ways, butxerrors
only permitted validating that initial draft. I think this was a mistake.Testing out new designs in
x/exp
or some other non-std repo is an excellent idea, but next time let's do it in a way that allows us to iterate on the design, whether that means frequent versioning (set/v1
,set/v2
, etc.) or accepting that incompatible changes will be made to the experimental package to keep it in sync with the eventual design.43 remaining items