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

[DON'T MERGE] Indirect availability declarations #29559

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

lorentey
Copy link
Member

@lorentey lorentey commented Jan 31, 2020

This is a proof of concept for a variant of @available that copies availability information from another declaration. This would fix a pain point for us ABI-stable library developers by eliminating redundant availability incantations and simplifying the error-prone and onerously manual task of finalizing them before stable releases.

@available(macOS 10.14.4, iOS 12.2, watchOS 5.2, tvOS 12.1, *)
internal typealias _Stdlib_5_0 = Void

@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
internal typealias _Stdlib_5_1 = Void

@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
internal typealias _Stdlib_Dev = Void


@_availableRef(_Stdlib_5_1)
public struct CollectionDifference<ChangeElement> { ... }

@_availableRef(_Stdlib_Dev)
public struct FancyNewStdlibFeature { ... }

@_availableRef is an implementation detail that doesn't affect the public interface of the module. (It gets expanded into the actual @available list on serialization.)

Notes:

  1. I have no idea what I'm doing here. 😅

  2. We'll also need some equivalent of this for if #available, so that we can use this in tests as well. (Maintaining #available tests in unit tests is currently at least tricky as @available attributes are in the actual code.)

  3. We need to decide how we want to spell this. Perhaps it makes sense to roll this functionality into @available itself. (Something like @available(at: _Stdlib_5_1)?)

  4. TypeRefinementContextBuilder resolves/propagates availability information before @available attributes are type checked, which seems backward to me. @_availableRef needs to resolve its target type -- I'm not sure if it's okay to do name resolution this early in the type checking process.

  5. The argument of @_availableRef is currently restricted to a type name -- for extra points, it would be nice if it could refer to other kind of decls (enum cases especially).

  6. Using dummy type declarations for this seems like a hack. What if we introduced dedicated syntax for declaring aliases for shorthand-style availability declarations?

    #versiondef(stdlib 5.0: macOS 10.14.4, iOS 12.2, watchOS 5.2, tvOS 12.1, *)
    #versiondef(stdlib 5.1: macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
    #versiondef(stdlib dev: macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)

    This would get rid of the need to resolve decl names, and it would allow us to use nice version tuples instead of ugly identifiers like _Stdlib_5_1 . It could also simplify deprecations/obsoletions:

    @available(stdlib 5.1)
    func foo() { ... }
    @available(stdlib, introduced: 5.1, deprecated: 9.4, message: "blah blah")
    func bar() { ... }
    
    func baz() {
      if #available(stdlib 7.5) { ... }
    }

    Note how this solves point (3) above -- it basically reuses the existing syntax for OS version numbers. (With some weirdness about how this interacts with the shorthand fallback platform *.)

@lorentey
Copy link
Member Author

@brentdax @slavapestov @xymus: Would something like this be a reasonable idea? (This would only help a tiny audience, but maintaining availability declarations is one use of the C preprocessor that we cannot replicate in Swift yet.)

@karwa
Copy link
Contributor

karwa commented Jan 31, 2020

This would only help a tiny audience

I disagree. I would love this. It's common to write the same long availability strings everywhere in your project, and it would be nice to have a shorter way to do it.

@lorentey
Copy link
Member Author

@karwa Ah, interesting. The driving force behind this idea was to make it easier to update a whole bunch of availability declarations at once — e.g., when we need to replace all the 9999 placeholders with actual version numbers in preparation of a release.

I haven’t considered how it could be applied to code that calls ABI-stable APIs. 🤔

@_availableRef(SwiftUI.View)
struct MyView: View {...}

Would this be a good idea? I’m honestly not sure — I can see how it would get rid of the need to figure out the correct incantation, but I don’t think I’d like reading code without the explicit availability lists. Hm.

@shahmishal
Copy link
Member

Please update the base branch to main by Oct 5th otherwise the pull request will be closed automatically.

  • How to change the base branch: (Link)
  • More detail about the branch update: (Link)

@lorentey lorentey changed the base branch from master to main October 2, 2020 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants