Would it be possible to create operators?

let total = manager[@sum.reports.salary]


> On Mar 18, 2017, at 22:00 , Muse M via swift-evolution 
> <[email protected]> wrote:
> 
> I would suggest a keypath using ~ which is concise and clearer to identify.
> 
>       let myPath = Person~friends[0].name
> 
> 
> 
> 
> 
> On Sunday, March 19, 2017, Jonathan Hull via swift-evolution 
> <[email protected]> wrote:
> This looks fantastic!
> 
> The one worry I would have, as others have brought up, is confusion when 
> there are static properties with the same name.  Maybe we could have a 
> special static property called ‘keyPath’ or ‘path’ that would be reserved, 
> and anything that followed would be a key path.
> 
> So instead of:
> 
>       let myPath = Person.friends[0].name
> 
> you would have:
> 
>       let myPath = Person.keyPath.friends[0].name
> 
> 
> Or if we want to choose a sentinel, I would nominate ‘$’:
> 
>       let myPath = $Person.friends[0].name
> 
> Thanks,
> Jon
> 
> 
>> On Mar 17, 2017, at 10:04 AM, Michael LeHew via swift-evolution 
>> <[email protected]> wrote:
>> 
>> Hi friendly swift-evolution folks,
>> 
>> The Foundation and Swift team  would like for you to consider the following 
>> proposal:
>> 
>> Many thanks,
>> -Michael
>> 
>> Smart KeyPaths: Better Key-Value Coding for Swift
>>      • Proposal: SE-NNNN
>>      • Authors: David Smith, Michael LeHew, Joe Groff
>>      • Review Manager: TBD
>>      • Status: Awaiting Review
>>      • Associated PRs:
>>              • #644
>> Introduction
>> We propose a family of concrete Key Path types that represent uninvoked 
>> references to properties that can be composed to form paths through many 
>> values and directly get/set their underlying values.
>> 
>> Motivation
>> We Can Do Better than String
>> 
>> On Darwin platforms Swift's existing #keyPath() syntax provides a convenient 
>> way to safely refer to properties. Unfortunately, once validated, the 
>> expression becomes a String which has a number of important limitations:
>> 
>>      • Loss of type information (requiring awkward Any APIs)
>>      • Unnecessarily slow to parse
>>      • Only applicable to NSObjects
>>      • Limited to Darwin platforms
>> Use/Mention Distinctions
>> 
>> While methods can be referred to without invoking them (let x = foo.bar 
>> instead of  let x = foo.bar()), this is not currently possible for 
>> properties and subscripts.
>> 
>> Making indirect references to a properties' concrete types also lets us 
>> expose metadata about the property, and in the future additional behaviors.
>> 
>> More Expressive KeyPaths
>> 
>> We would also like to support being able to use Key Paths to access into 
>> collections, which is not currently possible.
>> 
>> Proposed solution
>> We propose introducing a new expression akin to Type.method, but for 
>> properties and subscripts. These property reference expressions produce 
>> KeyPath objects, rather than Strings. KeyPaths are a family of generic 
>> classes (structs and protocols here would be ideal, but requires generalized 
>> existentials) which encapsulate a property reference or chain of property 
>> references, including the type, mutability, property name(s), and ability to 
>> set/get values.
>> 
>> Here's a sample of it in use:
>> 
>> Swift
>> struct Person {
>> 
>>     
>> var name: String
>> 
>>     
>> var friends: [Person]
>> 
>>     
>> var bestFriend: Person?
>> }
>> 
>> 
>> 
>> var han = Person(name: "Han Solo", friends: [])
>> var luke = Person(name: "Luke Skywalker", friends: [han])
>> 
>> 
>> 
>> let firstFriendsNameKeyPath = Person.friends[0].
>> name
>> 
>> 
>> let firstFriend = luke[path] // han
>> 
>> 
>> 
>> // or equivalently, with type inferred from context
>> let firstFriendName = luke[.friends[0].name]
>> 
>> 
>> 
>> // rename Luke's first friend
>> 
>> luke
>> [firstFriendsNameKeyPath] = "A Disreputable Smuggler"
>> 
>> 
>> 
>> let bestFriendsName = luke[.bestFriend]?.name  // nil, if he is the last jedi
>> Detailed design
>> Core KeyPath Types
>> 
>> KeyPaths are a hierarchy of progressively more specific classes, based on 
>> whether we have prior knowledge of the path through the object graph we wish 
>> to traverse. 
>> 
>> Unknown Path / Unknown Root Type
>> 
>> AnyKeyPath is fully type-erased, referring to 'any route' through an 
>> object/value graph for 'any root'. Because of type-erasure many operations 
>> can fail at runtime and are thus nillable. 
>> 
>> Swift
>> class AnyKeyPath: CustomDebugStringConvertible, Hashable {
>> 
>>     
>> // MARK - Composition
>> 
>>     
>> // Returns nil if path.rootType != self.valueType
>> 
>>     
>> func appending(path: AnyKeyPath) -> AnyKeyPath?
>> 
>>     
>>     
>> // MARK - Runtime Information        
>> 
>>     
>> class var rootType: Any.Type
>> 
>>     
>> class var valueType: Any.Type
>> 
>>     
>>     
>> static func == (lhs: AnyKeyPath, rhs: AnyKeyPath) -> Bool
>> 
>>     
>> var hashValue: Int
>> }
>> Unknown Path / Known Root Type
>> 
>> If we know a little more type information (what kind of thing the key path 
>> is relative to), then we can use PartialKeyPath <Root>, which refers to an 
>> 'any route' from a known root:
>> 
>> Swift
>> class PartialKeyPath<Root>: AnyKeyPath {
>> 
>>     
>> // MARK - Composition
>> 
>>     
>> // Returns nil if Value != self.valueType
>> 
>>     
>> func appending(path: AnyKeyPath) -> PartialKeyPath<Root>?
>> 
>>     
>> func appending<Value, AppendedValue>(path: KeyPath<Value, AppendedValue>) -> 
>> KeyPath<Root, AppendedValue>?
>> 
>>     
>> func appending<Value, AppendedValue>(path: ReferenceKeyPath<Value, 
>> AppendedValue>) -> ReferenceKeyPath<Root, AppendedValue>?
>> }
>> Known Path / Known Root Type
>> 
>> When we know both what the path is relative to and what it refers to, we can 
>> use KeyPath. Thanks to the knowledge of the Root and Value types, all of the 
>> failable operations lose their Optional. 
>> 
>> Swift
>> public class KeyPath<Root, Value>: PartialKeyPath<Root> {
>> 
>>     
>> // MARK - Composition
>> 
>>     
>> func appending<AppendedValue>(path: KeyPath<Value, AppendedValue>) -> 
>> KeyPath<Root, AppendedValue>
>> 
>>     
>> func appending<AppendedValue>(path: WritableKeyPath<Value, AppendedValue>) 
>> -> Self
>> 
>>     
>> func appending<AppendedValue>(path: ReferenceWritableKeyPath<Value, 
>> AppendedValue>) -> ReferenceWritableKeyPath<Root, AppendedValue>
>> }
>> Value/Reference Mutation Semantics Mutation
>> 
>> Finally, we have a pair of subclasses encapsulating value/reference mutation 
>> semantics. These have to be distinct because mutating a copy of a value is 
>> not very useful, so we need to mutate an inout value.
>> 
>> Swift
>> class WritableKeyPath<Root, Value>: KeyPath<Root, Value> {
>> 
>>     
>> // MARK - Composition
>> 
>>     
>> func appending<AppendedPathValue>(path: WritableKeyPath<Value, 
>> AppendedPathValue>) -> WritableKeyPath<Root, AppendedPathValue>
>> }
>> 
>> 
>> 
>> class ReferenceWritableKeyPath<Root, Value>: WritableKeyPath<Root, Value> {
>> 
>>     
>> override func appending<AppendedPathValue>(path: WritableKeyPath<Value, 
>> AppendedPathValue>) -> ReferenceWritableKeyPath<Root, AppendedPathValue>
>> }
>> Access and Mutation Through KeyPaths
>> 
>> To get or set values for a given root and key path we effectively add the 
>> following subscripts to all Swift types. 
>> 
>> Swift
>> extension Any {
>> 
>>     
>> subscript(path: AnyKeyPath) -> Any? { get }
>> 
>>     
>> subscript<Root: Self>(path: PartialKeyPath<Root>) -> Any { get }
>> 
>>     
>> subscript<Root: Self, Value>(path: KeyPath<Root, Value>) -> Value { get }
>> 
>>     
>> subscript<Root: Self, Value>(path: WritableKeyPath<Root, Value>) -> Value { 
>> set, get }
>> }
>> This allows for code like
>> 
>> Swift
>> person[.name] // Self.type is inferred
>> which is both appealingly readable, and doesn't require read-modify-write 
>> copies (subscripts access self inout). Conflicts with existing subscripts 
>> are avoided by using generic subscripts to specifically only accept key 
>> paths with a Root of the type in question.
>> 
>> Referencing Key Paths
>> 
>> Forming a KeyPath borrows from the same syntax used to reference methods and 
>> initializers,Type.instanceMethod only now working for properties and 
>> collections. Optionals are handled via optional-chaining. Multiply dotted 
>> expressions are allowed as well, and work just as if they were composed via 
>> the appending methods on KeyPath.
>> 
>> There is no change or interaction with the #keyPath() syntax introduced in 
>> Swift 3. 
>> 
>> Performance
>> 
>> The performance of interacting with a property via KeyPaths should be close 
>> to the cost of calling the property directly.
>> 
>> Source compatibility
>> This change is additive and there should no affect on existing source. 
>> 
>> Effect on ABI stability
>> This feature adds the following requirements to ABI stability: 
>> 
>>      • mechanism to access key paths of public properties
>> We think a protocol-based design would be preferable once the language has 
>> sufficient support for generalized existentials to make that ergonomic. By 
>> keeping the class hierarchy closed and the concrete implementations private 
>> to the implementation it should be tractable to provide compatibility with 
>> an open protocol-based design in the future.
>> 
>> Effect on API resilience
>> This should not significantly impact API resilience, as it merely provides a 
>> new mechanism for operating on existing APIs.
>> 
>> Alternatives considered
>> More Features
>> 
>> Various drafts of this proposal have included additional features 
>> (decomposable key paths, prefix comparisons, support for custom 
>> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution


-- 
Rick Mann
[email protected]


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to