There was something called Optional Chaining in Swift, but if the language specification supports such missiles, I would like you to support arrays and other similar (monamona) ones.
I think it's new, but as you know, optional chains
struct Person {
let name: String
let age: Int
let friends: [Person]
}
let me: Person = .init(name: "Freddie", age: 30, friends: [])
let someone = me.friends.first?.friends.first?.friends.first // <- Person?
You can access properties continuously using?
But the question is, why doesn't this syntax support arrays and Result types?
The reason why we cite options and arrays to be treated equally is that they are very long, so I will omit them in the explanation that "these are common monads." Roughly speaking, both optional and array have member functions such as map and flatMap, and they are similar to each other, aren't they? That's it.
What I want to do is to write in an array like this dream.
let people: [Person] = [.init(name: "me", age: 32, friends: [.init(name: "Tom", age: 40, friends: [])]), .init(name: "you", age: 28, friends: [.init(name: "Nancy", age: 10, friends: []), .init(name: "Freddie", age: 20, friends: [])])]
let totalAge = people[].age.reduce(0, +) // 60
let ourFriends = people[].friends[].name // ["Tom", "Nancy", "Freddie"]
If you name it, it's called Array Chaining.
people[].age
Wouldn't it be short and beautiful if it could be written this way?
Good
people.map { $0.age }
Or at best
people.map(\.age)
Let's say goodbye to a masala town level code like this.
This time I'm dealing with arrays, so I'm going to use [] instead of the signal to use the method chain.
public extension Collection {
subscript() -> ArrayMemberLookupReference<Self> {
.init(source: self)
}
}
public extension Collection where Element: Collection {
subscript() -> ArrayMemberLookupReference<[Element.Element]> {
.init(source: lazy.flatMap { $0 })
}
}
@dynamicMemberLookup
public struct ArrayMemberLookupReference<C: Collection> {
fileprivate let source: C
}
extension ArrayMemberLookupReference {
subscript<Property>(dynamicMember keyPath: KeyPath<C.Element, Property>) -> [Property] {
source.map { t in t[keyPath: keyPath] }
}
}
By the way, you may wonder if such a thing can really be used. Let me show you the sample code again.
struct Person {
let name: String
let age: Int
let friends: [Person]
}
let people: [Person] = [.init(name: "me", age: 32, friends: [.init(name: "Tom", age: 40, friends: [])]), .init(name: "you", age: 28, friends: [.init(name: "Nancy", age: 10, friends: []), .init(name: "Freddie", age: 20, friends: [])])]
let totalAge = people[].age.reduce(0, +) // 60
let ourFriends = people[].friends[].name // ["Tom", "Nancy", "Freddie"]
If you suspect that it will actually work, try running it on Playground. It's actually implemented in the current Swift, but it looks as if a new language specification has been added.
Recommended Posts