[swift-evolution] Pitch: Support for map and flatMap with smart key paths

Karl Wagner razielim at gmail.com
Fri Jun 9 18:51:28 CDT 2017


> On 10. Jun 2017, at 01:42, Karl Wagner <razielim at gmail.com> wrote:
> 
>> 
>> On 8. Jun 2017, at 04:58, Tony Allevato via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> +1, I really like this. It would also align nicely with the method type flattening in SE-0042 <https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md> (once it gets implemented), because passing keypaths (i.e., unbound property references) and unbound parameterless method references to map/flatMap would look nearly the same:
>> 
>> ```
>> struct Person {
>>   let firstName: String
>>   let lastName: String
>>   func fullName() -> String { return "\(firstName) \(lastName)" }
>> }
>> 
>> let people: [Person]
>> let firstNames = people.map(\.firstName)
>> let fullNames = people.map(Person.fullName)  // because after SE-0042, this will be (Person) -> String, not (Person) -> () -> String
>> ```
>> 
>> Especially if there's a move in the future to also use \. to denote unbound methods references, which was discussed during the keypath reviews. (Even with that, I believe it would be more work though to get rid of the explicit type name in the function case.)
>> 
>> 
> 
> When it comes to unbound method references, personally, I would love to see us ditch currying in some future version of Swift and move to full-blown partial application instead. We would need variadic generics if we wanted to expose them as nicely-typed objects as we do with KeyPaths.
> 
> Anyway, I think what you want is something like this (where VirtualKeyPath is a custom subclass of KeyPath which is lazily-evaluated using a closure).
> 
> extension KeyPath where Value: Collection {
>     func map<T>(_ descendent: KeyPath<Value, T>) -> VirtualKeyPath<Root, [T]> {
>         return VirtualKeyPath<Root, [T]> { 
>             (obj: Root) -> [T] in obj[keypath: self].map { $0[keypath: descendent] } 
>         }
>     }
> }
> 
> \Department.people.map(\.fullName).characters.count  // type: VirtualKeyPath<Department, [Int]>
> 
> 
> Custom subclasses of KeyPath are not allowed, so you can’t actually do this. I don’t know, maybe it wouldn’t be much overhead to add the one, closure-based VirtualKeyPath — clearly the architecture is meant to be flexible. Maybe it’s better to wait until Swift 5 for that, though.
> 
> - Karl

Two corrections to myself:

1) It’s KeyPath<Value.Element, T>

2) You could implement VirtualKeyPath today, but you wouldn’t get the chaining syntax. You’d have to just keep map-ping it every time:

\Department.people.map(\.fullName).map(\.characters.count)  // type: VirtualKeyPath<Department, [Int]>

- Karl

> 
>> On Wed, Jun 7, 2017 at 6:11 PM Xiaodi Wu via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> +1. Would think that all variants should exist on Optional too unless it would be harmful.
>> On Wed, Jun 7, 2017 at 20:13 Michael J LeHew Jr via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> This is a great idea, and ought to be easy enough to bring forward!  +1 from me!
>> 
>> -Michael
>> 
>> > On Jun 7, 2017, at 11:18 AM, Matt Diephouse via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> >
>> > 💯
>> >
>> >> On Jun 7, 2017, at 10:35 AM, Adam Sharp via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> >>
>> >> The new smart key path feature is really lovely, and feels like a great addition to Swift.
>> >>
>> >> It seems like it might be straightforward to add overloads of `map` and `flatMap` to the standard library to make use of the new functionality:
>> >>
>> >>      let managers = flatOrganisation.managers
>> >>      let allEmployees = Set(managers.flatMap(\.directReports))
>> >>      let employeeNames = Set(allEmployees.map(\.name))
>> >>
>> >> This feels like a really natural way of working with key paths in a functional style. It makes a lot of sense for collections, and possibly for Optional too (although as far as I can see optional chaining is more or less equivalent, and with more compact syntax).
>> >>
>> >> I’m hoping that this might be low-hanging fruit that could be considered for the Swift 4 release. I’d be happy to have a go at writing a proposal if there’s interest!
>> >>
>> >> –Adam
>> >>
>> >> _______________________________________________
>> >> swift-evolution mailing list
>> >> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> >> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> >
>> > _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> > https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170610/517d3aa3/attachment.html>


More information about the swift-evolution mailing list