diff --git a/0000-template.md b/0000-template.md index 014fc590f0..816b171b6f 100644 --- a/0000-template.md +++ b/0000-template.md @@ -2,7 +2,7 @@ * Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md) * Author(s): [Swift Developer](https://github.com/swiftdev) -* Status: **Awaiting review** +* Status: **[Awaiting review](#rationale)** * Review manager: TBD ## Introduction @@ -50,3 +50,10 @@ automatically? Describe alternative approaches to addressing the same problem, and why you chose this approach instead. +------------------------------------------------------------------------------- + +# Rationale + +On Smarch 13, 20XX, the core team decided to **(TBD)** this proposal. +When the core team makes a decision regarding this proposal, +their rationale for the decision will be written here. diff --git a/README.md b/README.md index 913019c993..d2fd7c21c5 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ sampling of potentially good ideas that are not in scope for Swift * [SE-0037: Clarify interaction between comments & operators](proposals/0037-clarify-comments-and-operators.md) * [SE-0040: Replacing Equal Signs with Colons For Attribute Arguments](proposals/0040-attributecolons.md) * [SE-0043: Declare variables in 'case' labels with multiple patterns](proposals/0043-declare-variables-in-case-labels-with-multiple-patterns.md) +* [SE-0046: Establish consistent label behavior across all parameters including first labels](proposals/0046-first-label.md) * [SE-0053: Remove explicit use of `let` from Function Parameters](proposals/0053-remove-let-from-function-parameters.md) ### Accepted proposals for Swift 3.0 @@ -127,7 +128,6 @@ sampling of potentially good ideas that are not in scope for Swift * [SE-0039: Modernizing Playground Literals](proposals/0039-playgroundliterals.md) * [SE-0042: Flattening the function type of unapplied method references](proposals/0042-flatten-method-types.md) * [SE-0044: Import as Member](proposals/0044-import-as-member.md) -* [SE-0046: Establish consistent label behavior across all parameters including first labels](proposals/0046-first-label.md) * [SE-0047: Defaulting non-Void functions so they warn on unused results](proposals/0047-nonvoid-warn.md) * [SE-0054: Abolish `ImplicitlyUnwrappedOptional` type](proposals/0054-abolish-iuo.md) * [SE-0055: Make unsafe pointer nullability explicit using Optional](proposals/0055-optional-unsafe-pointers.md) @@ -180,3 +180,4 @@ sooner. ### Deferred for Future Discussion * [SE-0026: Abstract classes and methods](proposals/0026-abstract-classes-and-methods.md) +* [SE-0058: Allow Swift types to provide custom Objective-C representations](proposals/0058-objectivecbridgeable.md) diff --git a/proposals/0009-require-self-for-accessing-instance-members.md b/proposals/0009-require-self-for-accessing-instance-members.md index e36cbbc62d..c2c185862e 100644 --- a/proposals/0009-require-self-for-accessing-instance-members.md +++ b/proposals/0009-require-self-for-accessing-instance-members.md @@ -9,6 +9,8 @@ The current version of Swift (2.1) requires using `self` when accessing instance members in closures. The proposal suggests extending this to all member accesses (as is intrinsically the case in Objective-C). It has the benefit of documenting instance properties vs local variables and instance functions vs local functions or closures. +[Swift Evolution Discussion Thread](http://thread.gmane.org/gmane.comp.lang.swift.evolution/9526) + ## Motivation This proposal makes it obvious which are instance properties vs local variables, as well as which are instance functions vs local functions/closures. This has several advantages: diff --git a/proposals/0010-add-staticstring-unicodescalarview.md b/proposals/0010-add-staticstring-unicodescalarview.md index 79ca3b17c4..5b7b5af41f 100644 --- a/proposals/0010-add-staticstring-unicodescalarview.md +++ b/proposals/0010-add-staticstring-unicodescalarview.md @@ -10,6 +10,8 @@ There is no way to create a substring of a `StaticString` that is still typed as `StaticString`. There should be. +[Swift Evolution Discussion Thread](http://thread.gmane.org/gmane.comp.lang.swift.evolution/9366), [Review](http://thread.gmane.org/gmane.comp.lang.swift.evolution/2434) + ## Motivation It is occasionally useful to be able to produce a substring of a `StaticString` diff --git a/proposals/0011-replace-typealias-associated.md b/proposals/0011-replace-typealias-associated.md index 00b3f34ba4..8c5d9947d8 100644 --- a/proposals/0011-replace-typealias-associated.md +++ b/proposals/0011-replace-typealias-associated.md @@ -18,6 +18,8 @@ confusion surrounding the use of associated types. The proposed new keyword is `associatedtype`. +[Swift Evolution Discussion Thread](http://thread.gmane.org/gmane.comp.lang.swift.evolution/9301) + ## Motivation Re-using `typealias` for associated type declarations is confusing in many ways. diff --git a/proposals/0012-add-noescape-to-public-library-api.md b/proposals/0012-add-noescape-to-public-library-api.md index 2beb382a3d..83c2fef125 100644 --- a/proposals/0012-add-noescape-to-public-library-api.md +++ b/proposals/0012-add-noescape-to-public-library-api.md @@ -17,6 +17,8 @@ * We propose exposing this attribute in CF and Foundation as `CF_NOESCAPE` and `NS_NOESCAPE` * We also propose applying this declaration to a number of closure-taking APIs in CF and Foundation +[Swift Evolution Discussion Thread](http://thread.gmane.org/gmane.comp.lang.swift.corelibs/53) + ## Introduction ### `@noescape` diff --git a/proposals/0013-remove-partial-application-super.md b/proposals/0013-remove-partial-application-super.md index 110645c2ee..b59df5316d 100644 --- a/proposals/0013-remove-partial-application-super.md +++ b/proposals/0013-remove-partial-application-super.md @@ -22,6 +22,8 @@ those mechanisms, I propose that we disallow partial application of non-final methods through `super`, except where the `self` parameter is implicitly captured. +[Swift Evolution Discussion Thread](http://thread.gmane.org/gmane.comp.lang.swift.evolution/9778), [Review](http://thread.gmane.org/gmane.comp.lang.swift.evolution/2880) + ## Motivation The motivation of this change is partially motivated by implementation diff --git a/proposals/0014-constrained-AnySequence.md b/proposals/0014-constrained-AnySequence.md index 6ba2ba2056..85bbb399a0 100644 --- a/proposals/0014-constrained-AnySequence.md +++ b/proposals/0014-constrained-AnySequence.md @@ -10,6 +10,8 @@ In order to allow `AnySequence` delegate calls to the underlying sequence, its initializer should have extra constraints. +[Swift Evolution Discussion](http://thread.gmane.org/gmane.comp.lang.swift.evolution/1893) + ## Motivation At the moment `AnySequence` does not delegate calls to `SequenceType` protocol diff --git a/proposals/0015-tuple-comparison-operators.md b/proposals/0015-tuple-comparison-operators.md index 78c608fd34..631dac2289 100644 --- a/proposals/0015-tuple-comparison-operators.md +++ b/proposals/0015-tuple-comparison-operators.md @@ -9,6 +9,10 @@ Implement comparison operators on tuples up to some arity. +[Initial Discussion](http://article.gmane.org/gmane.comp.lang.swift.evolution/980/match=tuple+comparison), [General Discussion](http://thread.gmane.org/gmane.comp.lang.swift.evolution/9723), [Review](http://thread.gmane.org/gmane.comp.lang.swift.evolution/11423/focus=732) + +Note: The review was initially started on the wrong thread with the wrong title and subsequently corrected. + ## Motivation It's annoying to try and compare tuples of comparable values and discover that diff --git a/proposals/0016-initializers-for-converting-unsafe-pointers-to-ints.md b/proposals/0016-initializers-for-converting-unsafe-pointers-to-ints.md index 3ff4cf0cb8..947c3993cc 100644 --- a/proposals/0016-initializers-for-converting-unsafe-pointers-to-ints.md +++ b/proposals/0016-initializers-for-converting-unsafe-pointers-to-ints.md @@ -13,6 +13,8 @@ allow users to call C functions with `intptr_t` and `uintptr_t` parameters, and allow users to perform more advanced pointer arithmetic than is allowed by `UnsafePointer`s. +[Swift Evolution Discussion](http://thread.gmane.org/gmane.comp.lang.swift.evolution/10044), [Review](http://thread.gmane.org/gmane.comp.lang.swift.evolution/12696) + ## Motivation ## Swift currently lacks the ability to perform many complex operations on diff --git a/proposals/0017-convert-unmanaged-to-use-unsafepointer.md b/proposals/0017-convert-unmanaged-to-use-unsafepointer.md index 141df29ca8..ba1ff7a8ed 100644 --- a/proposals/0017-convert-unmanaged-to-use-unsafepointer.md +++ b/proposals/0017-convert-unmanaged-to-use-unsafepointer.md @@ -9,6 +9,8 @@ The standard library [`Unmanaged` struct](https://github.com/apple/swift/blob/master/stdlib/public/core/Unmanaged.swift) provides a type-safe object wrapper that does not participate in ARC; it allows the user to make manual retain/release calls. +[Swift Evolution Discussion](http://thread.gmane.org/gmane.comp.lang.swift.evolution/9877), [Proposed Rewrite Discussion](http://thread.gmane.org/gmane.comp.lang.swift.evolution/68/) + ## Motivation The following methods are provided for converting to/from Unmanaged: diff --git a/proposals/0019-package-manager-testing.md b/proposals/0019-package-manager-testing.md index c41106ee03..7c91ed6a29 100644 --- a/proposals/0019-package-manager-testing.md +++ b/proposals/0019-package-manager-testing.md @@ -13,6 +13,8 @@ Testing is an essential part of modern software development. Tight integration of testing into the Swift Package Manager will help ensure a stable and reliable packaging ecosystem. +[SE Review Link](http://thread.gmane.org/gmane.comp.lang.swift.evolution/3583) + ## Proposed Solution We propose to extend our conventional package directory layout diff --git a/proposals/0058-objectivecbridgeable.md b/proposals/0058-objectivecbridgeable.md index 68959c9806..622d11f7a6 100644 --- a/proposals/0058-objectivecbridgeable.md +++ b/proposals/0058-objectivecbridgeable.md @@ -2,7 +2,7 @@ * Proposal: SE-0058 * Author(s): [Russ Bishop](https://github.com/russbishop), [Doug Gregor](https://github.com/DougGregor) -* Status: **Review** +* Status: **[Deferred](#rationale)** * Review manager: [Joe Groff](https://github.com/jckarter) @@ -243,3 +243,22 @@ This can always be implemented in the future if it is desired. It is intended that when and if Swift 3 adopts conditional protocol conformance that the standard library types such as `Array` and `Dictionary` will declare conditional conformance to `ObjectiveCBridgeable` if their element types are `ObjectiveCBridgeable` (with explicitly declared conformance for built-ins like `Int`). +------------------------------------------------------------------------------- + +# Rationale + +On April 12, 2016, the core team decided to **defer** this proposal from +Swift 3. We agree that it would be valuable to give library authors the +ability to bridge their own types from Objective-C into Swift using the +same mechanisms as Foundation. However, we lack the confidence and +implementation experience to commit to `_ObjectiveCBridgeable` in its +current form as public API. In its current form, as its name suggests, the +protocol was designed to accommodate the specific needs of bridging +Objective-C object types to Swift value types. In the future, we may +want to bridge with other platforms, including C++ value types or +other object systems such as COM, GObject, JVM, or CLR. It isn't clear at +this point whether these would be served by a generalization of the existing +mechanism, or by bespoke bridging protocols tailored to each case. This +is a valuable area to explore, but we feel that it is too early at this +point to accept our current design as public API. + diff --git a/proposals/0062-objc-keypaths.md b/proposals/0062-objc-keypaths.md new file mode 100644 index 0000000000..e2578a2aa6 --- /dev/null +++ b/proposals/0062-objc-keypaths.md @@ -0,0 +1,86 @@ +# Referencing Objective-C key-paths + +* Proposal: [SE-0062](https://github.com/apple/swift-evolution/blob/master/proposals/0062-objc-keypaths.md) +* Author(s): [David Hart](https://github.com/hartbit) +* Status: **Under review** (April 7...12, 2016) +* Review manager: [Doug Gregor](https://github.com/DougGregor) + +## Introduction + +In Objective-C and Swift, key-paths used by KVC and KVO are represented as string literals (e.g., `"friend.address.streetName"`). This proposal seeks to improve the safety and resilience to modification of code using key-paths by introducing a compiler-checked expression. + +## Motivation + +The use of string literals for key paths is extremely error-prone: there is no compile-time assurance that the string corresponds to a valid key-path. In a similar manner to the proposal for the Objective-C selector expression [SE-0022](https://github.com/apple/swift-evolution/blob/master/proposals/0022-objc-selectors.md), this proposal introduces syntax for referencing compiler-checked key-paths. When the referenced properties and methods are renamed or deleted, the programmer will be notified by a compiler error. + +## Proposed solution + +Introduce a new expression `#keyPath()` that allows one to build a compile-time valid key-path string literal (to allow it be used as `StaticString` and `StringLiteralConvertible`): + +```swift +class Person: NSObject { + dynamic var firstName: String = "" + dynamic var lastName: String = "" + dynamic var friends: [Person] = [] + dynamic var bestFriend: Person? + + init(firstName: String, lastName: String) { + self.firstName = firstName + self.lastName = lastName + } +} + +let chris = Person(firstName: "Chris", lastName: "Lattner") +let joe = Person(firstName: "Joe", lastName: "Groff") +let douglas = Person(firstName: "Douglas", lastName: "Gregor") +chris.friends = [joe, douglas] +chris.bestFriend = joe + + +#keyPath(Person.firstName) // => "firstName" +chris.valueForKey(#keyPath(Person.firstName)) // => Chris +#keyPath(Person.bestFriend.lastName) // => "bestFriend.lastName" +chris.valueForKeyPath(#keyPath(Person.bestFriend.lastName)) // => Groff +#keyPath(Person.friends.firstName) // => "friends.firstName" +chris.valueForKeyPath(#keyPath(Person.friends.firstName)) // => ["Joe", "Douglas"] +``` + +By having the `#keyPath` expression do the work to form the Objective-C key-path string, we free the developer from having to do the manual typing and get static checking that the key-path exists and is exposed to Objective-C. + +It would also be very convenient for the `#keyPath` to accept value (instead of static) expressions: + +``` +extension Person { + class func find(name: String) -> [Person] { + return DB.execute("SELECT * FROM Person WHERE \(#keyPath(firstName)) LIKE '%\(name)%'") + } +} +``` + +In this case, `#keyPath(firstName)` is understood to represent `#keyPath(Person.firstName)`. + +## Collection Keypaths + +As Foundation types are not strongly-typed, the key-path expression should only accept traversing `SequenceType` conforming types: + +```swift +let swiftArray = ["Chris", "Joe", "Douglas"] +let nsArray = NSArray(array: swiftArray) +swiftArray.valueForKeyPath(#keyPath(swiftArray.count)) // => 3 +swiftArray.valueForKeyPath(#keyPath(swiftArray.uppercased)) // => ["CHRIS", "JOE", "DOUGLAS"] +swiftArray.valueForKeyPath(#keyPath(nsArray.count)) // => 3 +swiftArray.valueForKeyPath(#keyPath(nsArray.uppercaseString)) // compiler error +``` +There is some implicit bridging going on here that could use some detailed design. If I refer to `Person.lastName.uppercased`, that's a method on the value type `String`. At runtime, we're depending on getting the `uppercaseString` method on `NSString`. This may be as simple as saying that we follow the `_ObjectiveCBridgeable` conformance for any value type encountered along the way. + +## Collection Operators + +This proposal purposely does not attempt to implement Collection Operators as the current functionality stands on its own and is useful even without the Objective-C runtime (as can be seen in the previous example). On the contrary, collection operators will require more design, and are only useable with `valueForKeyPath:` which is not available on Linux. + +## Impact on existing code + +The introduction of the `#keyPath` expression has no impact on existing code, and is simply a modification-safe alternative to using strings literal for referencing key-paths. + +## Alternatives considered + +There does not seem to be any obvious alternatives. The only point of discussion was on the name of the expression. `#key` was proposed: it is shorter but does not seem to express that the expression accepts paths. \ No newline at end of file diff --git a/proposals/0063-swiftpm-system-module-search-paths.md b/proposals/0063-swiftpm-system-module-search-paths.md new file mode 100644 index 0000000000..99ab9726ef --- /dev/null +++ b/proposals/0063-swiftpm-system-module-search-paths.md @@ -0,0 +1,207 @@ +# SwiftPM System Module Search Paths + +* Proposal: [SE-0063](https://github.com/apple/swift-evolution/blob/master/proposals/0063-swiftpm-system-module-search-paths.md) +* Author: [Max Howell](https://github.com/mxcl) +* Status: **Under review** (April 7...13, 2016) +* Review manager: [Anders Bertelrud](https://github.com/abertelrud) + + +## Introduction + +Swift is able to `import` C libraries in the same manner as Swift libraries. + +For this to occur the library must be represented by a clang module-map file. + +The current system for using these module-map files with SwiftPM works, but with +a number of caveats that must be addressed. + + +[swift-evolution thread](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160321/013201.html) + + +## Terminology + +* **SwiftPM Source Package**: A package consumed by SwiftPM that comes with sources that SwiftPM builds into modules +* **SwiftPM System Package**: A package consumed by SwiftPM that refers to a modular system library not installed by SwiftPM +* **System Package**: A package provided by a system packager like, eg. `apt`, `pacman` or `brew`. +* **System Packager**: A system package manager like, eg. `apt`, `pacman` or `brew`. + + +## Motivation + +The current implementation of SwiftPM System Packages have a number of problems: + + 1. Install locations vary across platforms and `.modulemap` files require absolute paths + 2. `/usr/lib:/usr/local/lib` is not always a sufficient `-L` linker search path + 3. `/usr/include:/usr/local/include` is not always a sufficient `-I` C compiler search path + 4. Installing the system library is left up to the end-user to figure out + +For example to import a module map representing the GTK library, the include search +path must be supplemented with `-I/usr/include/gtk` so that a number of includes in +the `gtk.h` header can be sourced for the complete modular definition of GTK. + +For example to import a module map representing the GTK library a user must first have +a copy of GTK and its headers installed. On Debian based systems the install name for +this System Package is `libgtk-3-0-dev` which is not entirely intuitive. + +For example, Homebrew and MacPorts on OS X install to prefixes other than `/usr`. +`.modulemap` files must specify headers with absolute paths. The standard we +encourage with modulemaps is for the headers to be specified with an assumed +prefix of `/usr`, but you will not find eg. `jpeglib.h` at `/usr/include/jpeglib.h` +if it is installed with Homebrew or MacPorts. + + +## Proposed Solution + +We propose that SwiftPM gains the ability to read `.pc` files written for the +cross-platform `pkg-config` tool. These files describe the missing search paths +that SwiftPM requires. They also specify the install location of system libraries +and will allow SwiftPM to preprocess the modulemap changing the specified header +prefixes. + +We propose that `Package.swift` is supplemented with metadata that provides the +package-install-name for specific platforms. + + +## Detailed Design + +### Solving Path/Flags Issues + +A system library should provide a pkg-config file (`.pc`) which describes: + + 1. Its install location + 2. Supplementary flags that should be used when compiling against this library + 3. Supplementary flags that should be used when linking against this library + +If SwiftPM read the `.pc` file that comes with System Packages, this solves problems 1 through 3. + +Of the tickets we currently have open describing issues using SwiftPM System Packages, +reading the `.pc` file would fix all of them. + +It is a convention to name the `.pc` file after the library link-name, so we can determine +which `.pc` file to ask `pkg-config` for by parsing the `.modulemap` file in the SwiftPM Package. +However sometimes this is not true, (eg. GTK-3 on Ubuntu), so we will allow an override in +the `Package.swift` file, for example: + +```swift +let package = Package( + name: "CFoo", + pkgConfigName: "gtk-3" +) +``` + +Thus we would search for a filename: `gtk-3.pc`. + +We don’t want to introduce a new dependency (on `pkg-config`) to Swift, so we will +implement the reading of `.pc` files according to the pkg-config specification, including: + + 1. Obeying the correct search .pc file search paths + 2. Following overrides due to any `PKG_CONFIG_PATH` environment variable + + +### Hinting At System-Package Install-Names + +`Package.swift` would be supplemented like so: + +```swift +let package = Package( + name: "CFoo", + pkgConfigName: "foo", + providers: [ + .Brew(installName: "foo"), + .Apt(installName: "libfoo-dev"), + ], +) +``` + +Thus, in the event of build failure for modules that depend on this +SwiftPM Package we would output additional help to the user: + +``` +error: failed to build module `bar' +note: you may need to install `foo' using your system-packager: + + apt-get install libfoo-dev +``` + +Since the syntax to provide this information uses an explicit enum we can +add code for each enum to detect which system packagers should be +recommended. The community will need to write the code for their own +platforms. It also means that if a specific system-packager requires additional +parameters, they can be added on a per enum basis. + +#### Install-names are not standard + +`apt` is used across multiple distirbutions and the install-names for +tools vary. Even for the same distribution install-names may vary +across releases (eg. from Ubuntu 15.04 to Ubuntu 15.10) or even on +ocassion at finer granularity. + +We will not add explicit handling for this, but one can imagine the +enums for different system packagers could be supplemented in a backwards +compatible way to provide specific handling as real-world uses emerge, eg: + +```swift +case Apt(installName: String) + +// …could be adapted to: + +struct Debian: Linux {} +struct Ubuntu: Debian { + enum Variant { + case Gubuntu + case Kubuntu(Version) + } + enum Version { + case v1510 + case v1504 + } +} +case Apt(installName: String, distribution: Linux? = nil) +``` + +## Impact on Existing Code + +There will be no impact on existing code as this feature simply improves +an existing feature making new code possible. + + +## Alternatives Considered + +A clear alternative is allowing additional flags to be specified in a SwiftPM System Package’s `Package.swift`. + +However since these paths and flags will vary by platform this would because a large matrix that is quite a maintenance burden. Really this information is recorded already, in the System Package itself, and in fact almost all System Packages nowadays provide it in a `.pc` `pkg-config` file. + +Also we do not want to allow arbitrary flags to be specified in `Package.swift`, this allows packages too much power +to break a large dependency graph with bad compiles. The only entity that understands the whole graph and can manage +the build without breakage is SwiftPM, and allowing packages themselves to add arbitrary flags prevents SwiftPM from +being able to understand and control the build ensuring reliability and preventing “Dependency Hell”. + + +## Unsolved Problems + +Some (usually more legacy) system libraries do not provide `.pc` files instead they may provide +a tool named eg. `foo-config` that can be queried for compile and link flags. We do not yet +support these tools, and would prefer to take a wait and see approach to determine how +important supporting them may be. + +Some libraries on OS X do not come with `.pc` files. Again we'd like to see which libraries +are affected before potentially offering a solution here. + + +## Future Directions + +The build system could be made more reliable by having the specific system packager provide the information that this +proposal garners from `pkg-config`. For example, Homebrew installs everything into independent directories, using these +directories instead of more general POSIX search paths means there is no danger of edge-case search path collisions and the wrong libraries being picked up. + +If this was done `pkg-config` could become just one option for providing this data, and be used only as a fallback. + +--- + +We do not wish to provide a flag to automatically install dependencies via the +system packager. We feel this opens us up to security implications beyond the +scope of this tool. + +Instead we can provide JSON output that can be parsed and executed by some +other tooling developed outside of Apple. diff --git a/proposals/0064-property-selectors.md b/proposals/0064-property-selectors.md new file mode 100644 index 0000000000..0fe06cf50d --- /dev/null +++ b/proposals/0064-property-selectors.md @@ -0,0 +1,55 @@ +# Referencing the Objective-C selector of property getters and setters + +* Proposal: [SE-0064](https://github.com/apple/swift-evolution/blob/master/proposals/0064-property-selectors.md) +* Author(s): [David Hart](https://github.com/hartbit) +* Status: **Under review** (April 7...12, 2016) +* Review manager: [Doug Gregor](https://github.com/DougGregor) + +## Introduction + +Proposal [SE-0022](https://github.com/apple/swift-evolution/blob/master/proposals/0022-objc-selectors.md) was accepted and implemented to provide a `#selector` expression to reference Objective-C method selectors. Unfortunately, it does not allow referencing the getter and setter methods of properties. This proposal seeks to provide a design to reference those methods for the Swift 3.0 timeframe. + +[Original swift-evolution thread](http://article.gmane.org/gmane.comp.lang.swift.evolution/7614) +[Follow-up swift-evolution thread](http://thread.gmane.org/gmane.comp.lang.swift.evolution/7780) + +## Motivation + +The `#selector` expression is very useful but does not yet cover all cases. Accessing property getter and setters requires to drop down to the string syntax and forgo type-safety. This proposal supports this special case without introducing new syntax, but by introducing new overloads to the `#selector` compiler expression. + +## Proposed solution + +Introduce two new overrides to the `#selector` expression that allows building a selector which points to the getter or the setter of a property. + +```swift +class Person: NSObject { + dynamic var firstName: String + dynamic let lastName: String + dynamic var fullName: String { + return "\(firstName) \(lastName)" + } + + init(firstName: String, lastName: String) { + self.firstName = firstName + self.lastName = lastName + } +} + +let firstNameGetter = #selector(getter: Person.firstName) +let firstNameSetter = #selector(setter: Person.firstName) +``` + +Both overrides expect a property and the setter requires a variable property. For example, the following line of code would produce an error because the lastName property is defined with let. + +``` +let lastNameSetter = #selector(setter: Person.lastName) +// Argument of #selector(setter:) must refer to a variable property +``` + +## Impact on existing code + +The introduction of the new `#selector` overrides has no impact on existing code and could improve the string-literal-as-selector to `#selector` migrator. + +## Alternatives considered + +A long term alternive could arrise from the design of lenses in Swift. But as this is purely hypothetical and out of scope for Swift 3, this proposal fixes the need for referencing property selectors in a type-safe way straight-away. + diff --git a/proposals/0065-collections-move-indices.md b/proposals/0065-collections-move-indices.md new file mode 100644 index 0000000000..0135833a2c --- /dev/null +++ b/proposals/0065-collections-move-indices.md @@ -0,0 +1,687 @@ +# A New Model for Collections and Indices + +* Proposal: [SE-0065](https://github.com/apple/swift-evolution/blob/master/proposals/0065-collections-move-indices.md) +* Author(s): [Dmitri Gribenko](https://github.com/gribozavr), + [Dave Abrahams](https://github.com/dabrahams), + [Maxim Moiseev](https://github.com/moiseev) +* [Swift-evolution thread](http://news.gmane.org/find-root.php?message_id=CA%2bY5xYfqKR6yC2Q%2dG7D9N7FeY%3dxs1x3frq%3d%3dsyGoqYpOcL9yrw%40mail.gmail.com) +* Status: **Under Active review** April 10...18, 2016 +* Review manager: [Chris Lattner](https://github.com/lattner) +* Revision: 3 +* Previous Revisions: + [1](https://github.com/apple/swift-evolution/blob/21fac2e8034e79e4f44c1c8799808fc8cba83395/proposals/0065-collections-move-indices.md) + (as submitted), + [2](https://github.com/apple/swift-evolution/blob/1a821cf7ccbdf1d7566e9ce2e991bdd835ba3b7d/proposals/0065-collections-move-indices.md) + +## Summary + +We propose a new model for `Collection`s wherein responsibility for +index traversal is moved from the index to the collection itself. For +example, instead of writing `i.successor()`, one would write +`c.successor(i)`. We also propose the following changes as a +consequence of the new model: + +* A collection's `Index` can be any `Comparable` type. +* The distinction between intervals and ranges disappears, leaving + only ranges. +* A closed range that includes the maximal value of its `Bound` type + is now representable and does not trap. +* Existing “private” in-place index traversal methods are now available + publicly. + +## Motivation + +In collections that don't support random access, (string views, sets, +dictionaries, trees, etc.) it's very common that deriving one index +value from another requires somehow inspecting the collection's data. +For example, you could represent an index into a hash table as an +offset into the underlying storage, except that one needs to actually +look at *structure* of the hash table to reach the next bucket. In +the current model, supporting `i.successor()` means that the index +must additionally store not just an offset, but a reference to the +collection's structure. + +The consequences for performance aren't pretty: + +* Code that handles indices has to perform atomic reference counting, + which has significant overhead and can prevent the optimizer from + making other improvements. + +* Additional references to a collection's storage block the + library-level copy-on-write optimization: in-place mutation of + uniquely-referenced data. A live index makes underlying storage + non-uniquely referenced, forcing unnecessary copies when the + collection is mutated. In the standard library, `Dictionary` and + `Set` use a double-indirection trick to work around this issue. + Unfortunately, even this trick is not a solution, because (as we + have recently realized) it isn't threadsafe. [^1] + +By giving responsibility for traversal to the collection, we ensure +that operations that need the collection's structure always have it, +without the costs of holding references in indices. + +## Other Benefits + +Although this change is primarily motivated by performance, it has +other significant benefits: + +* Simplifies implementation of non-trivial indices. +* Allows us to eliminate the `Range`/`Interval` distinction. +* Making traversal a direct property of the `Collection` protocol, + rather than its associated `Index` type, is closer to most peoples' + mental model for collections, and simplifies the writing of many + generic constraints. +* Makes it feasible to fix existing concurrency issues in `Set` and + `Dictionary` indices. +* Allows `String` views to share a single index type, letting us + eliminate the need for cumbersome index conversion functions (not + part of this proposal, but planned). + +## Out of Scope + +This proposal intentionally does not: + +* Expand the set of concrete collections provided by the standard + library. +* Expand the set of collection protocols to provide functionality + beyond what is already provided (for example, protocols for sorted + collections, queues etc.) Discussing how other concrete collections + fit into the current protocol hierarchy is in scope, though. + +## Limitations of the Model + +Ideally, our collection model would allow us to implement every +interesting data structure with memory safety, optimal performance, +value semantics, and a variety of other useful properties such as +minimal invalidation of indexes upon mutation. In practice, these +goals and the Swift language model interact in complicated ways, +preventing some designs altogether, and suggesting a variety of +implementation strategies for others that can be selected based on +one's priorities. We've done some in-depth investigation of these +implications, but presenting and explaining them is well beyond the +scope of this proposal. + +We can, however, be fairly sure that this change does not regress our +ability to build any Collections that could have been built in Swift +2.2. After all, it is still *possible* to implement indices that store +references and have the old traversal methods (the collection's +traversal methods would simply forward to those of the index), so we +haven't lost the ability to express anything. + +## Overview of Type And Protocol Changes + +This section covers the proposed structural changes to the library at +a high level. Details such as protocols introduced purely to work +around compiler limitations (e.g. `Indexable` or `IndexableBase`) have +been omitted. For a complete view of the the code +and documentation changes implementing this proposal, please see this +[pull request](https://github.com/apple/swift/pull/2108). + +### Collection Protocol Hierarchy + +In the proposed model, indices don't have any requirements beyond +`Comparable`, so the `ForwardIndex`, `BidirectionalIndex`, and +`RandomAccessIndex` protocols are eliminated. Instead, we introduce +`BidirectionalCollection` and `RandomAccessCollection` to provide the +same traversal distinctions, as shown here: + +``` + +--------+ + |Sequence| + +---+----+ + | + +----+-----+ + |Collection| + +----+-----+ + | + +--------------+-------------+ + | | | + | +--------+--------+ | + | |MutableCollection| | + | +-----------------+ | + | | ++---------+-------------+ +---------+----------------+ +|BidirectionalCollection| |RangeReplaceableCollection| ++---------+-------------+ +--------------------------+ + | + +--------+-------------+ + |RandomAccessCollection| + +----------------------+ +``` + +These protocols compose naturally with the existing protocols +`MutableCollection` and `RangeReplaceableCollection` to describe a +collection's capabilities, e.g. + +```swift +struct Array + : RandomAccessCollection, + MutableCollection, + RangeReplaceableCollection { ... } + +struct UnicodeScalarView : BidirectionalCollection { ... } +``` + +### Range Protocols and Types + +The proposal adds several new types and protocols to support ranges: + +``` + +-------------+ + |RangeProtocol| + +------+------+ + | + +------------+---------------------+ + | | ++---------+-----------+ +----------+--------+ +|HalfOpenRangeProtocol| |ClosedRangeProtocol| ++----+------+---------+ : +-------+------+----+ + | | : | | ++----+---+ | +...........+...........+ | +---+----------+ +|Range| | : RandomAccessCollection: | |ClosedRange| ++========+ | +....+...............+..+ | +==============+ + | | | | + +----+-------+----+ +--+-----+--------------+ + |CountableRange| |CountableClosedRange| + +=================+ +=======================+ +``` + +* The old `Range`, `ClosedInterval`, and + `OpenInterval` are replaced with four new generic range types: + + * Two for general ranges (whose bounds are `Comparable`): `Range` + and `ClosedRange`. Having a separate `ClosedRange` type allows + us to address the vexing inability of the old `Range` to represent + a range containing the maximal value of its bound. + + * Two for ranges that additionally conform to + `RandomAccessCollection` (requiring bounds that are `Strideable` + with `Stride` conforming to `Integer`): `CountableRange` and + `CountableClosedRange`. These types can be folded into + `Range` and `ClosedRange` when Swift acquires conditional + conformance capability. + +We also introduce three new protocols: + +* `RangeProtocol` +* `HalfOpenRangeProtocol` +* `ClosedRangeProtocol` + +These protocols mostly exist facilitate implementation-sharing among +the range types, and would seldom need to be implemented outside the +standard library. + +### The Associated `Indices` Type + +The following code iterates over the indices of all elements in +`collection`: + +```swift +for index in collection.indices { ... } +``` + +In Swift 2, `collection.indices` returned a `Range`, but +because a range is a simple pair of indices and indices can no longer +be advanced on their own, `Range` is no longer iterable. + +In order to keep code like the above working, `Collection` has +acquired an associated `Indices` type that is always iterable, and +three generic types were introduced to provide a default `Indices` for +each `Collection` traversal category: `DefaultIndices`, +`DefaultBidirectionalIndices`, and `DefaultRandomAccessIndices`. +These types store the underlying collection as a means of traversal. +Collections like `Array` whose `Indices` don't need the collection +simply use `typealias Indices = CountableRange`. + +### Expanded Default Slice Types + +Because Swift doesn't support conditional protocol conformances and +the three traversal distinctions have been moved into the `Collection` +hierarchy, the four generic types `Slice`, `MutableSlice`, +`RangeReplaceableSlice`, and `MutableRangeReplaceableSlice` have +become twelve, with the addition of variations such as +`RangeReplaceableBidirectionalSlice`. + +### The `Comparable` Requirement on Indices + +In this model indices store the minimal amount of information required +to describe an element's position. Usually an index can be +represented with one or two `Int`s that efficiently encode the path to +the element from the root of a data structure. Since one is free to +choose the encoding of the “path”, we think it is possible to choose +it in such a way that indices are cheaply comparable. That has been +the case for all of the indices required to implement the standard +library, and a few others we investigated while researching this +change. + +It's worth noting that this requirement isn't strictly +necessary. Without it, though, indices would have no requirements +beyond `Equatable`, and creation of a `Range` would have to be +allowed for any `T` conforming to `Equatable`. As a consequence, most +interesting range operations, such as containment checks, would be +unavailable unless `T` were also `Comparable`, and we'd be unable to +provide bounds-checking in the general case. + +That said, the requirement has real benefits. For example, it allows +us to support distance measurement between arbitrary indices, even in +collections without random access traversal. In the old model, +`x.distance(to: y)` for these collections had the undetectable +precondition that `x` precede `y`, with unpredictable consequences for +violation in the general case. + +## Detailed API Changes + +This section describes changes to methods, properties, and associated +types at a high level. Details related to working around compiler +limitations have been omitted. For a complete view of the the code +and documentation changes implementing this proposal, please see this +[pull request](https://github.com/apple/swift/pull/2108). + +### `Collection`s + +The following APIs were added: + +```swift +protocol Collection { + ... + /// A type that can represent the number of steps between pairs of + /// `Index` values where one value is reachable from the other. + /// + /// Reachability is defined by the ability to produce one value from + /// the other via zero or more applications of `successor(_)`. + associatedtype IndexDistance : SignedInteger = Int + + /// A collection type whose elements are the indices of `self` that + /// are valid for subscripting, in ascending order. + associatedtype Indices : Collection = DefaultIndices + + /// The indices that are valid for subscripting `self`, in ascending order. + /// + /// - Note: `indices` can hold a strong reference to the collection itself, + /// causing the collection to be non-uniquely referenced. If you need to + /// mutate the collection while iterating over its indices, use the + /// `successor(_)` method starting with `startIndex` to produce indices + /// instead. + /// + /// ``` + /// var c = [10, 20, 30, 40, 50] + /// var i = c.startIndex + /// while i != c.endIndex { + /// c[i] /= 5 + /// i = c.successor(i) + /// } + /// // c == [2, 4, 6, 8, 10] + /// ``` + var indices: Indices { get } + + /// Returns the position immediately after `i`. + /// + /// - Precondition: `(startIndex.. Index + + /// Replaces `i` with its successor. + func formSuccessor(i: inout Index) + + /// Returns the result of advancing `i` by `n` positions. + /// + /// - Returns: + /// - If `n > 0`, the `n`th successor of `i`. + /// - If `n < 0`, the `n`th predecessor of `i`. + /// - Otherwise, `i` unmodified. + /// + /// - Precondition: `n >= 0` unless `Self` conforms to + /// `BidirectionalCollection`. + /// - Precondition: + /// - If `n > 0`, `n <= self.distance(from: i, to: self.endIndex)` + /// - If `n < 0`, `n >= self.distance(from: i, to: self.startIndex)` + /// + /// - Complexity: + /// - O(1) if `Self` conforms to `RandomAccessCollection`. + /// - O(`abs(n)`) otherwise. + func location(i: Index, offsetBy n: IndexDistance) -> Index + + /// Returns the result of advancing `i` by `n` positions, or until it + /// equals `limit`. + /// + /// - Returns: + /// - If `n > 0`, the `n`th successor of `i` or `limit`, whichever + /// is reached first. + /// - If `n < 0`, the `n`th predecessor of `i` or `limit`, whichever + /// is reached first. + /// - Otherwise, `i` unmodified. + /// + /// - Precondition: `n >= 0` unless `Self` conforms to + /// `BidirectionalCollection`. + /// + /// - Complexity: + /// - O(1) if `Self` conforms to `RandomAccessCollection`. + /// - O(`abs(n)`) otherwise. + func location( + i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index + + /// Advances `i` by `n` positions. + /// + /// - Precondition: `n >= 0` unless `Self` conforms to + /// `BidirectionalCollection`. + /// - Precondition: + /// - If `n > 0`, `n <= self.distance(from: i, to: self.endIndex)` + /// - If `n < 0`, `n >= self.distance(from: i, to: self.startIndex)` + /// + /// - Complexity: + /// - O(1) if `Self` conforms to `RandomAccessCollection`. + /// - O(`abs(n)`) otherwise. + func formLocation(i: inout Index, offsetBy n: IndexDistance) + + /// Advances `i` by `n` positions, or until it equals `limit`. + /// + /// - Precondition: `n >= 0` unless `Self` conforms to + /// `BidirectionalCollection`. + /// + /// - Complexity: + /// - O(1) if `Self` conforms to `RandomAccessCollection`. + /// - O(`abs(n)`) otherwise. + func formLocation( + i: inout Index, offsetBy n: IndexDistance, limitedBy limit: Index) + + /// Returns the distance between `start` and `end`. + /// + /// - Precondition: `start <= end` unless `Self` conforms to + /// `BidirectionalCollection`. + /// - Complexity: + /// - O(1) if `Self` conforms to `RandomAccessCollection`. + /// - O(`n`) otherwise, where `n` is the method's result. + func distance(from start: Index, to end: Index) -> IndexDistance +} + +protocol BidirectionalCollection { + /// Returns the position immediately preceding `i`. + /// + /// - Precondition: `i > startIndex && i <= endIndex` + func predecessor(_ i: Index) -> Index + + /// Replaces `i` with its predecessor. + /// + /// - Precondition: `i > startIndex && i <= endIndex` + func formPredecessor(i: inout Index) +} +``` + +Note: + +* The mutating `formSuccessor`, `formPredecessor`, and the `formIndex` + overloads essentially enshrine the previously-hidden + `_successorInPlace` et al., which can be important for performance + when handling the rare heavyweight index type such as `AnyIndex`. + +* `RandomAccessCollection` does not add any *syntactic* requirements + beyond those of `BidirectionalCollection`. Instead, it places + tighter performance bounds on operations such as `c.location(i, + offsetBy: n)` (O(1) instead of O(`n`)). + +## `Range`s + +The `RangeProtocol` shown below, along with the description of +[Range Protocols and Types](#range-protocols-and-types) above, provide +a complete picture of the changes to ranges. + +```swift +/// A type that represents a contiguous range of any comparable value. +/// +/// A range contains at least every value `x` where `lowerBound < x` and +/// `x < upperBound`. Individual types that conform to `RangeProtocol` must +/// specify their containment rules for the bounds of the range. +/// +/// The standard library defines two kinds of ranges: closed ranges, +/// represented by `ClosedRangeProtocol`, and half-open ranges, represented by +/// `HalfOpenRangeProtocol`. A closed range contains both its lower and upper +/// bounds, and therefore cannot be empty. A half-open range, on the other +/// hand, contains its lower bound when nonempty but never its upper bound. +/// +/// let closed: ClosedRange = 5...10 +/// closed.contains(5) // true +/// closed.contains(10) // true +/// +/// let halfOpen: Range = 5..<10 +/// halfOpen.contains(5) // true +/// halfOpen.contains(10) // false +/// +/// Not all empty ranges are equal; the bounds of two empty ranges must also be +/// equal for the ranges to be equal. +public protocol RangeProtocol : Equatable { + + /// The representation of the range's endpoints and the values + /// contained in it. + associatedtype Bound : Comparable + + /// Creates an instance with the given bounds. + /// + /// - Note: As this initializer does not check its precondition, it + /// should be used as an optimization only, when one is absolutely + /// certain that `lower <= upper`. In general, the `..<` and `...` + /// operators are to be preferred for forming ranges. + /// + /// - Precondition: `lower <= upper` + init(uncheckedBounds: (lower: Bound, upper: Bound)) + + /// Returns `true` if the range contains the `value`. + /// + /// Any type of range contains every value `x` where + /// `lowerBound < x < upperBound`. `RangeProtocol` makes no requirement as + /// to whether individual range types must contain either their lower or + /// upper bound. + func contains(value: Bound) -> Bool + + /// Returns `true` iff `self` and `other` contain a value in common. + /// + /// Any type of range contains every value `x` where + /// `lowerBound < x < upperBound`. `RangeProtocol` makes no requirement as + /// to whether individual range types must contain either their lower or + /// upper bound. + func overlaps(other: Self) -> Bool + + /// Returns `true` iff `self.contains(x)` is `false` for all values of `x`. + var isEmpty: Bool { get } + + // Note: When the range is also a collection, it is crucial to + // enforce the invariant that lowerBound <= upperBound, or it may be + // empty with startIndex != endIndex. + + /// The range's lower bound. + /// + /// Depending on the concrete type of the range, `lowerBound` may or may not + /// be contained in the range. + var lowerBound: Bound { get } + + /// The range's upper bound. + /// + /// Depending on the concrete type of the range, `upperBound` may or may not + /// be contained in the range. + var upperBound: Bound { get } + + /// Returns `self` clamped to `limits`. + /// + /// The bounds of the result, even if it is empty, are always + /// limited to the bounds of `limits`. + func clamped(to limits: Self) -> Self +} + +/// Conversion from one range to another. +extension RangeProtocol where Bound : Strideable, Bound.Stride : Integer { + /// Creates an instance equivalent to `other`. + /// + /// - Precondition: an equivalent range is representable as an + /// instance of `Self`. For example, `Range(0...Int.max)` + /// violates this precondition because an equivalent `Range` + /// would need an `upperBound` equal to `Int.max + 1`, which + /// is unrepresentable as an `Int`. + public init(_ other: Other) +} +``` + +Note in particular: + +* In `Range`, `T` is `Comparable` rather than an index + type that can be advanced, so a generalized range is no longer a + `Collection`, and `startIndex`/`endIndex` have become + `lowerBound`/`upperBound`. +* The semantic order of `Interval`'s `clamp` method, which was + unclear at its use-site, has been inverted and updated with a + preposition for clarity. + +## Downsides + +The proposed approach has several disadvantages, which we explore here +in the interest of full disclosure: + +* In Swift 2, `RandomAccessIndex` has operations like `+` that provide + easy access to arbitrary position offsets in some collections. That + could also be seen as discouragement from trying to do random access + operations with less-refined index protocols, because in those cases + one has to resort to constructs like `i.advancedBy(n)`. In this + proposal, there is only `c.location(i, offsetBy: n)`, which makes + random access equally (in)convenient for all collections, and there + is no particular syntactic penalty for doing things that might turn + out to be inefficient. + +* Index movement is more complex in principle, since it now involves + not only the index, but the collection as well. The impact of this + complexity is limited somewhat because it's very common that code + moving indices occurs in a method of the collection type, where + “implicit `self`” kicks in. The net result is that index + manipulations end up looking like free function calls: + + ```swift + let j = successor(i) // self.successor(i) + let k = location(j, offsetBy: 5) // self.location(j, offsetBy: 5) + ``` + +* The + [new index manipulation methods](https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Collection.swift#L135) + increase the API surface area of `Collection`, which is already + quite large since algorithms are implemented as extensions. + +* Because Swift is unable to express conditional protocol + conformances, implementing this change has required us to create a + great deal of complexity in the standard library API. Aside from + the two excess “`Countable`” range types, there are new overloads + for slicing and twelve distinct slice types that capture all the + combinations of traversal, mutability, and range-replaceability. + While these costs are probably temporary, they are very real in the + meantime. + +* The API complexity mentioned above stresses the type checker, + requiring + [several](https://github.com/apple/swift/commit/1a875cb922fa0c98d51689002df8e202993db2d3) + [changes](https://github.com/apple/swift/commit/6c56af5c1bc319825872a25041ec33ab0092db05) + just to get our test code to type-check in reasonable time. Again, + an ostensibly temporary—but still real—cost. + +## Impact on existing code + +Code that **does not need to change**: + +* Code that works with `Array`, `ArraySlice`, `ContiguousArray`, and + their indices. + +* Code that operates on arbitrary collections and indices (on concrete + instances or in generic context), but does no index traversal. + +* Iteration over collections' indices with `c.indices` does not change. + +* APIs of high-level collection algorithms don't change, even for + algorithms that accept indices as parameters or return indices (e.g., + `index(of:)`, `min()`, `sort()`, `prefix()`, `prefix(upTo:)` etc.) + +Code that **needs to change**: + +* Code that advances indices (`i.successor()`, `i.predecessor()`, + `i.advanced(by:)` etc.) or calculates distances between indices + (`i.distance(to:)`) now needs to call a method on the collection + instead. + + ```swift + // Before: + var i = c.index { $0 % 2 == 0 } + let j = i.successor() + print(c[j]) + + // After: + var i = c.index { $0 % 2 == 0 } // No change in algorithm API. + let j = c.successor(i) // Advancing an index requires a collection instance. + print(c[j]) // No change in subscripting. + ``` + + The transformation from `i.successor()` to `c.successor(i)` is + non-trivial. Performing it correctly requires knowing how to get + the corresponding collection. In general, it is not possible to + perform this migration automatically. A very sophisticated migrator + could handle some easy cases. + +* Custom collection implementations need to change. A simple fix would + be to just move the the methods from indices to collections to satisfy + new protocol requirements. This is a more or less mechanical fix that + does not require design work. This fix would allow the code to + compile and run. + + In order to take advantage of performance improvements in + the new model, and remove reference-counted stored properties from + indices, the representation of the index might need to be redesigned. + + Implementing custom collections, as compared to using collections, is + a niche case. We believe that for custom collection types it is + sufficient to provide clear steps for manual migration that don't + require a redesign. Implementing this in an automated migrator might + be possible, but would be a heroic migration for a rare case. + +## Implementation Status + +[This pull request](https://github.com/apple/swift/pull/2108) contains +a complete implementation. + +## Alternatives considered + +We considered index-less models, for example, [D's +std.range](https://dlang.org/library/std/range.html) (see also [On +Iteration by Andrei +Alexandrescu](http://www.informit.com/articles/printerfriendly/1407357)). +Ranges work well for reference-typed collections, but it is not clear +how to adjust the concept of D's range (similar to `Slice` in Swift) for +mutable value-typed collections. In D, you process a collection by +repeatedly slicing off elements. Once you have found an element that +you would like to mutate, it is not clear how to actually change the +original collection, if the collection and its slice are value types. + +---- + +[^1]: `Dictionary` and `Set` use a double-indirection trick to avoid +disturbing the reference count of the storage with indices. + +``` + +--+ class struct + |RC|---------+ +-----------------+ + +--+ Storage |<---------| DictionaryIndex | + | | | value | + +----------+ +-----------------+ + ^ + +--+ | class struct + |RC|-------------+ +------------+ + +--+ Indirection |<-------| Dictionary | + | ("owner") | | value | + +--------------+ +------------+ +``` + +Instances of `Dictionary` point to an indirection, while +instances of `DictionaryIndex` point to the storage itself. +This allows us to have two separate reference counts. One of +the refcounts tracks just the live `Dictionary` instances, which +allows us to perform precise uniqueness checks. + +The issue that we were previously unaware of is that this scheme +is not thread-safe. When uniquely-referenced storage is being +mutated in place, indices can be concurrently being incremented +(on a different thread). This would be a read/write data race. + +Fixing this data race (to provide memory safety) would require +locking dictionary storage on every access, which would be an +unacceptable performance penalty. diff --git a/proposals/00XX-universal-Self.md b/proposals/00XX-universal-Self.md new file mode 100644 index 0000000000..def98fa8c9 --- /dev/null +++ b/proposals/00XX-universal-Self.md @@ -0,0 +1,59 @@ +# Expanding Swift `Self` to class members and value types + +* Proposal: [SE-XXXX](https://gist.github.com/erica/5a26d523f3d6ffb74e34d179740596f7) +* Author(s): [Erica Sadun](http://github.com/erica) +* Status: TBD +* Review manager: TBD + +## Introduction + +Within a class scope, `Self` means "the dynamic class of `self`". This proposal extends that courtesy to value types, where dynamic `Self` will match a construct's static type, and to the bodies of class members, where it may not. It also introduces a static variation, `#Self` that expands to static type of the code it appears within. + +This proposal was discussed on the Swift Evolution list in the [\[Pitch\] Adding a Self type name shortcut for static member access](http://thread.gmane.org/gmane.comp.lang.swift.evolution/13708/focus=13712) thread. + +## Motivation + +It is common in Swift to reference an instance's type, whether for accessing +a static member or passing a type for an unsafe bitcast, among other uses. +At this time, you can either fully specify a type by name or use `self.dynamicType` +to access an instance's dynamic runtime type as a value. + +``` +struct MyStruct { + static func staticMethod() { ... } + func instanceMethod() { + MyStruct.staticMethod() + self.dynamicType.staticMethod() + } +} +``` + +Introducing `Self` addresses the following issues: + +* As type names grow large, readability suffers. `MyExtremelyLargeTypeName.staticMember` is unwieldy to type and read. +* Code using hardwired type names is less portable than code that automatically knows its type. +* Renaming a type means updating any `TypeName` references in code. +* Using `self.dynamicType` fights against Swift's goals of concision and clarity in that it is both noisy and esoteric. +* `self.dynamicType.classMember` and `TypeName.classMember` may not be synonyms in class types with non-final members. + +## Detail Design + +This proposal introduces `Self` and `#Self`. + +* `Self` equates to the dynamic type of `self` and only the +dynamic type of `self`. You will continue to specify full type +names for any other use. Joe Groff writes, "I don't think it's all +that onerous to have to write `ClassName.foo` if that's really what +you specifically mean." + +* `#Self` expands to the static type of the code it is +declared within. In value types, this is always the same as `Self`. +`#Self` will offer a literal textual replacement just like `#file`, etc. + +## Alternatives Considered + +Not at this time + +## Acknowlegements + +Thanks Sean Heber, Kevin Ballard, Joe Groff, Timothy Wood, Brent Royal-Gordon, Andrey Tarantsov, Austin Zheng \ No newline at end of file diff --git a/schedule.md b/schedule.md index c9cf5108e9..1a66033533 100644 --- a/schedule.md +++ b/schedule.md @@ -12,7 +12,10 @@ proposals in that process. * March 31...April 5, 2016 [SE-0056: Allow trailing closures in `guard` conditions](proposals/0056-trailing-closures-in-guard.md) * March 31...April 5, 2016 [SE-0036: Requiring Leading Dot Prefixes for Enum Instance Member Implementations](proposals/0036-enum-dot.md) * March 31...April 5, 2016 [SE-0059: Update API Naming Guidelines and Rewrite Set APIs Accordingly](proposals/0059-updated-set-apis.md) -* April 4...11, 2016 [SE-0058: Allow Swift types to provide custom Objective-C representations](proposals/0058-objectivecbridgeable.md) +* April 7...12, 2016 [SE-0062: Referencing Objective-C key-paths](proposals/0062-objc-keypaths.md) +* April 7...13, 2016 [SE-0063: SwiftPM System Module Search Paths](proposals/0063-swiftpm-system-module-search-paths.md) +* April 7...12, 2016 [SE-0064: Referencing the Objective-C selector of property getters and setters](proposals/0064-property-selectors.md) +* April 10...18, 2016 [SE-0065: A New Model For Collections and Indices](proposals/0065-collections-move-indices.md) ## Upcoming reviews