SE-0264 — Standard Library Preview Package

The review of SE-0264 — Standard Library Preview Package begins now and runs through Sept 30, 2019

The proposal is written by @ben_cohen, @moiseev, and @nnnnnnnn.

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager (via email or direct message in the Swift forums).

What goes into a review of a proposal?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift.

When reviewing a proposal, here are some questions to consider:

  • What is your evaluation of the proposal?
  • Is the problem being addressed significant enough to warrant a change to Swift?
  • Does this proposal fit well with the feel and direction of Swift?
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Thanks,
Dave Abrahams
Review Manager

23 Likes

I think all about I can say is this is long, long overdue! I think this is an excellent idea and has precedent in various forms in many languages, and generally works well.

One thing I feel needs some more clarity is what exactly counts as an "unexpected problem" that requires re-evolution. I understand this will probably vary case by case, but I would really hate to see too many evolutions revisions for a single stdlib feature come up. I know that API design can be tricky to get right, and it's always super tempting to keep tweaking/adding to the design, but at a certain point you just have to ship it, or say it can't work. So I would assume a problem requiring re-evolution would be something that has significant performance/usability issues stemming from the actual API design, rather than some specific implementation of it.

Another thing (which is closely related to the above point) is I didn't see (or I missed) is how proposals should be treated that build/extend on things that are still only in the preview package. Should we discourage "improvements" to an accepted proposal until after a certain time (it ships?). Or should we encourage people to suggest improvements? This again ties into the idea of having too many evolutions proposals causing burnout.

But overall, I think this is a welcome change.

1 Like

I'm a huge fan of this proposal. +1.

A couple of questions:
GYB is disallowed in the preview package (I agree with this decision) but the proposal could be more explicit about what that means for additions that could really benefit from GYB (for example, additions that would benefit from variadic generics if they were available); is this motivation to (a) add those types/functions straight to the standard library or is it motivation to (b) write those additions once without GYB and then port to GYB when porting to the standard library or is this an opportunity to (c) move further away from GYB in the standard library as well (even for sufficiently repetitive code)?

The decision when to tag minor versions will be made by the release manager for the standard library as chosen by the Swift project lead.

Why won't there just be a new version for every accepted proposal?

Will there be an official guide to contributing to the preview package? The proposal is not at all unwieldy, but a more concise guide could definitely help reduce the amount of ad-hoc explaining needed during pitch phases and additionally feed into the explicit goal of lowering the barrier to entry of contribution.

2 Likes
  • What is your evaluation of the proposal?
    +1 A desirable change, making it easier to adopt and give real-world feedback about new stdlib features.

  • Is the problem being addressed significant enough to warrant a change to Swift?
    Yes

  • Does this proposal fit well with the feel and direction of Swift?
    Yes

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
    A quick reading.

However, this would be too restricting at this time, as a branch-based dependency can only be imported by other branch-based dependencies. This would effectively limit use of the SwiftPreview package to top-level applications only.

How is a versioned package going to use SwiftPreview? Won't the frequent source breakages lead to dependency hell if it is used in versioned source-stable packages?

1 Like

Modifications would be held to the same high bar of justifying a change or addition as an original proposal, with only the source-stability requirement loosened. As always, the hope is that we'll determine the right additions and behavior during the pitch and review phases, so only truly unanticipated problems would be cause for a revision. Improvements to implementations are always welcome without going through the evolution process.

Since all additions to the package will eventually land in the standard library, it will be natural for some proposals to build on past additions. If there's a natural set of functionality that grows out of an addition, hopefully we'll find that during the discussion of the initial proposal and either include it or create a bit of a roadmap for follow-on proposals.

This is essentially the plan; I'll make a note of that in the proposal.

Definitely!

I think the answer here is "carefully". In general, libraries that declare themselves source-stable should not depend on the preview package, but we don't want to put a technical limitation in place that would make it problematic for people who want to modularize their projects.

When two additions land at exactly the same time, there are benefits to coalescing them into the single version bump.

1 Like

+1 I think this is a great addition to Swift.

+1 finally! quick read some investigation.

Wondering why there couldn’t be method selection through disambiguation. The function example where .SwiftPreview is proposed is defined precisely in the Function + Type below, for the .lazy. This would give a hard requirement that, as a preview, I could access a subtype defining a bridge to the Swift or the SwiftPreview implementation. That would cost a single indirection, a pointer back and some further internal work to create and maintain those bridges in the Preview part. It could also make sure the code is actually consistent internally as not all the Preview types could be fully ABI compatible (yet) with its peer.

I also have concerns over functionalities being forwarded into code from a library dependency. Let’s pretend a library/package (mine or 3rd party) internally uses Preview code for its own internal use because it allows a great functionality. I want to make sure the SwiftPreview library doesn’t act like a virus and can be contained, as its unwitting usage might cause instabilities or a behaviour different than expected.

+1 for me as well.

As I said in the pitch thread I'm generally in favor of this proposal. However, as I mentioned there (with no reply), I am not entirely satisfied with the one year cycle for removing API that has migrated to the standard library.

I think we should seriously consider a separate stream of releases that always requires the latest released version of Swift (or later) and drops any symbols that have moved to the standard library as of that Swift release. This would provide a better alternative for users who do want to update quickly to the latest version of Swift. It would also ensure more immediate usage of the library implementations because users of the "edge" release would not need to modify code to switch to the library's implementation. In order to avoid confusion this version of the preview could have a different module name (i.e. SwiftPreviewEdge or something like that).

Supporting two streams of preview package releases is obviously more work for the package authors. However, I can speak from experience in saying that with appropriate planning it isn't terribly burdensome to support multiple build products from the same Swift sources.

One advantage having two streams of releases from the same source is that the Swift project contributors will gain experience in doing exactly that. It is possible this could motivate language features that would improve Swift's ability to fulfill this kind of requirement. (In some cases more boilerplate than is ideal)

If the core team decides it doesn't want to support two streams of release I think the one year timeline for staging features out of the preview package is much too long. When a new version of Swift is released it should be accompanied by a release of the preview package that does not include any symbols shipping in the standard library. This will ease adoption for those of who prefer to live on the bleeding edge. Users with slower update cycles are less likely to want to use the preview package anyway.

14 Likes

I like this proposal very much and think it will be a great addition to the ecosystem. But I was going to propose a modification similar to @anandabits

Specifically, I'm concerned about the proliferation and interweaving of arbitrary release numbers from the proposed scheme. We might have 0.134 that drops item X on schedule, 0.135 that adds item Y, and then 0.136 dropping Z. A user of the package has to keep track mentally of what they have access to at any given moment.

As an alternative, what about coalescing removal? Something along these lines:

  • As in the proposal, changes may be added freely to SwiftPreview, each with a minor version bump
  • As in the proposal, they may be added to the stdlib when ready/as time allows

BUT when a new release of the stdlib is made (yearly, I suppose, with Apple's release cycle):

  • All preview items that have moved to the stdlib are dropped from SwiftPreview at that time, AND
  • The major version of SwiftPreview is incremented

This provides us with a clear and easily describable progression for SwiftPreview: "Oh, yeah, FrobozzMagicSequence was moved to stdlib in v2, you need to update".

7 Likes

I support the idea, but I'm still not sure about the versioning part. As far as I remember, these sections of the proposal don't seem to have changed much since the discussion about this in pitch thread, and I find the reasoning here unclear. The text says that fixing the major version at 0 will act as a signal that it isn't source stable, but when I checked during the pitch thread it seemed that there is no special treatment major version 0 in the Swift package manager. What kind of chaos is this going to cause in dependency resolution? How does this signal anything to people who pick up this dependency transitively? Why is “proper” semantic versioning not even considered as an alternative?

The reason for keeping the zero-based major version was because it clearly signals the ongoing instability of the package, which will never converge as long as we continue to preview then land and release new features in the library.

Bumping the major version number would be contrary to this goal, without having a significant benefit (because minor versions would continue to add new features, which is in theory source breaking if not commonly so, or evolve APIs while still in preview, which is definitively so).

Indeed. It is a signal for humans, not for the package manager itself.

"Proper" semantic versioning would not bring any benefits, because when two packages both depend on an unstable package, they would have to agree on a version to use. When the major version is bumped constantly – because the goal of the package is to break source compatibility constantly (if only to add new API, which is technically source breaking) – then this would cause a logjam by giving the illusion of being useable by source-stable packages without actually being so in practice.

The fact is this package should not be pulled in by other packages that want to remain source stable. It would be nice to find a solution for these use cases too, but I've yet to see one, and holding up the preview package while we search for one, preventing apps and their supporting frameworks that could benefit from it. Once we do resolve this issue I hope we can adapt the process to use it.

  • What is your evaluation of the proposal?
    +1

  • Is the problem being addressed significant enough to warrant a change to Swift?
    Yes.

  • Does this proposal fit well with the feel and direction of Swift?
    Yes! It lowers the barrier for Standard Library Contributors in an ABI-Stable world, and will also lead to better real-world tested code landing into the Standard Library.

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
    N/A

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
    In-depth study.


Notes

  1. About the 1-year period for feature removal: Since the goal for this package is to be used in real-production code, I think the 1 year time period for features removal is fine; if we really want to push it down it could probably be a six months period.

  2. Something that I haven’t seen but I think is very important for this package to achieve its goal: how is this package going to be exposed to the community?

We need to push the SwiftPreview package so it can be used not only by the folks who participates in the forums.

I think this package deserves a spot or at least a mention in swift.org, it can be mentioned under the Standard Library Design section, or if it becomes important enough in the Swift community, it can be under the Projects section in the sidebar.

Also, the release of this package deserves a blog post in the Swift blog.

@Ben_Cohen can you clarify the implication of this sentence for me please?

The main difference from the existing process is that the final result will become available for general use immediately in a new version of the preview package.

Does this imply that unless the implementation of a particular feature requires some specific API from a stdlib version which is version locked, there will be no version locking? In that sense if diffing API's were implemented in the future and not in 5.1 then SwiftPreview package would have had this API's without @availabe(...) attributes, until it would officially move into stdlib?

1 Like

Is the “official” position that any new API addition in Swift is considered source breaking, and therefore requires a major version bump? This doesn't seem to square with the Swift Evolution definition of source stability, or with how semantic versioning is used by Swift packages today. I understand that it technically could be, because of overload resolution, etc. If you take a more reasonable (or lax, depending on your opinion) view here, then the major version would only need to be bumped when API is removed or changed in a source-incompatible way.

1 Like

The significance of this is that a new API with no @available(...) attached would be usable on an older OS in its SwiftPreview iteration, but not in its Standard Library iteration.


I was wondering this too. The semantic versioning standard says:

MINOR version when you add functionality in a backwards compatible manner, and
PATCH version when you make backwards compatible bug fixes.

What would possibly fall under a minor version, if not new APIs? Is Swift more vulnerable to creating new name clashes than the myriad other languages using the semantic version standard?

(I’m not arguing that we should or shouldn’t use version zero. I’m asking a broader question about how packages should be versioned in general.)

1 Like

Correct, that‘s what I hope, because it also has been mentioned that a user can (should) rip out the code from the package if he really needs it but the package itself removes it when it gets merged into stdlib.

I just want a clear clarification of that, otherwise I don‘t see the usefulness of this package besides that it will 'workaround' the slow release duration that we‘re used to from apple OS‘s.