Do you have any idea on the level of effort that would be required? I think it would be interesting to work on, but I am scared of C++ ![]()
I really don't want to discourage you, but I'll still give you my experiences with working on another pitch implementation as a beginner to the Swift compiler myself.
The Swift compiler is a very complex and hard to understand project. It sounds like you are not that experienced in C++, which makes it even quite a bit more complicated.
I began working on the first implementation of typed throws, together with a group of three other people, all of them with very little experience in the project. We made good progress implementing parsing for the change, but then we came to type-checking.
Let me say it like this: the type-checker of Swift is the single most complicated and hard to reason about piece of code, I've ever seen. Even though there is some documentation on the principles of its inner workings, it took basically endless code investigation until we could implement even the simplest things.
The project took so much longer than I anticipated that I had to stop working on it, just because of lack of time. It seems like it was similar for my teammates, as we haven't made more progress yet.
This all sounds very negative, so I'll state at least one positive aspect as well. If you really implement this feature, you will have gained really much knowledge about the inner workings of Swift but also compilers in general, which is very valuable and also applies to other fields.
If you are still interested in working on this implementation after this wall of text I created, I advise you to search somebody else, who is experienced with the compiler, to at least help you from time to time.
I would also offer to help you, but as I said, I currently have not enough time for that right now (and If I had, I would probably be working again on typed throws).
Hi ![]()
I have been looking at the discussion about using keypaths for unapplied methods. Seems like this thread is the latest mention about it. Appears like the proposal has potential and general acceptance, but the blocker is that it misses implementation.
Is this accurate? Has there been any other updates?
That is correct.
Iād love to work on implementing, but learning the guts of the Swift compiler enough to do so is not even close to the head of the priority queue for me, alas. I would welcome any assistance!
I ran in to this proposal last week and wondered if there might be a chance of getting some momentum behind it.
The use case Iāve got relates to closures in SwiftUI views. Closures not being equatable is a significant issue with SwiftUI and leads to view body reevaluation, which would be preferable to avoid.
With key paths to functions we could build something very close to a closure that would be equatable (and Hashable tooā¦).
It might look like thisā¦
struct Projection<Value>: Hashable {
let value: Value
private let identity: AnyHashable
init<Identity: Hashable>(
of identity: Identity,
keyPath: KeyPath<Identity, Value>
) {
self.value = identity[keyPath: keyPath]
self.identity = AnyHashable(identity)
}
static func ==(_ l: Self, _ r: Self) -> Bool { l.identity == r.identity }
func hash(into hasher: inout Hasher) { identity.hash(into: &hasher) }
}
/// We can hold one of these in a viewā¦
struct SomeView: View {
let action: Projection<() -> Void>
var body: some View {
Button("Hello", action: action.value)
}
}
We can build all that in Swift today.
However, we canāt call Projection<() -> Void>.init, because KeyPath doesnāt support function values (yet!).
The way I imagined this being used would be something likeā¦
final class AViewModel: Hashable {
var count = 0
func increment()
}
struct AView: View {
let model: AViewModel {
var body: some View {
SomeView(action: Projection(of: model, keyPath: \.action)
}
}
The gist is it lets make a kind of hashable closure by pointing to a specific (function) property of some other hashable type. That projected type provides the Hashable requirement. Providing the projected typeās Hashable implementation is reasonable, a key path projection of it will also be reasonable.
We could get something close using closures. Consider this extension to Projectionā¦
extension Projection {
init<Identity: Hashable>(
of identity: Identity,
with projection: (Identity) -> Value
) {
self.value = projection(identity)
self.identity = AnyHashable(identity)
}
}
Unfortunately, we can easily cheat this and get a Projection that remains equal when it should not be. Eg: Projection(of: model, with { _ doAnythingAtAllHere() }.
KeyPaths that allow function values give us a way to build something here that is safe and canāt be misused.