Key path cannot refer to static member

Hello,

The Swift 5.1 compiler won't let me create key paths to a static member:

struct S {
    static let member = 12
}

// Compiler error: Key path cannot refer to static member
let kp = \S.Type.member

In case this limitation was waiting for a use case... I have one.

The problem that needs a solution

Users of GRDB, the SQLite toolkit, happen to define static members when they define relationships between record types, the types that map the database tables:

// (Required protocol conformance stripped for brevity)
struct Player { ... }

struct Team {
    static let players = hasMany(Player.self)
}

Those static members have many usages. One of them is to access the associated records of a given record, as below. However, this code is quite heavy:

let team: Team = ...
let players = try team
    .request(for: Team.players)
    .fetchAll(database) // [Player]

In order to improve clarity at call site, users are advised to declare an extra property, as below:

struct Team {
    static let players = hasMany(Player.self)
    // One extra property...
    var players: QueryInterfaceRequest<Player> {
        request(for: Team.players)
    }
}

// ... for improved clarity:
let team: Team = ...
let players = try team.players.fetchAll(database)

The problem is this extra property. It is verbose, adds no information, is highly redundant, and, if useful, one can easily doubt it is worth the effort.

A solution: SE-0252 and key paths to static members

If key paths to those static members were possible, it would be possible to leverage SE-0252 Key Path Member Lookup and streamline a few database accesses:

// In an ideal world...
struct Player { ... }

@dynamicMemberLookup
struct Team {
    static let players = hasMany(Player.self)
}

// ... fetching all players from a team does not require more code
let team: Team = ...
let players = try team.players.fetchAll(database)
//                     ^ SE-0252

The user would only need to add @dynamicMemberLookup. It is the library that provides the implementation for the SE-0252 subscript:

// A default subscript that waits for @dynamicMemberLookup record types
extension TableRecord where Self: EncodableRecord {
    public subscript<A>(dynamicMember keyPath: KeyPath<Self.Type, A>)
        -> QueryInterfaceRequest<A.RowDecoder>
        where A: Association, A.OriginRowDecoder == Self
    {
        request(for: Self.self[keyPath: keyPath])
    }
}

Does any forum user know if key paths to static members require a Swift Evolution process, or if a report on bugs.swift.org would be enough?

32 Likes

IIRC it was part of @beccadax's static subscript proposal, but it was then dropped because it was too much for that proposal and maybe also a little hard to get implemented.

2 Likes

@DevAndArtist has a good memory—I tried to include this in SE-0254, but it wasn't the primary thrust of the proposal and I didn't finish implementing it in the limited time I could devote to a stretch goal. It seems totally doable, and might even be easy for someone who knows IRGen better than me—it just requires a lot of little corrections throughout the compiler. (When I stopped, I was in IRGen and still needed to make resilience work.)

I'm not a core team member, but I suspect that if there was a proposal and working implementation, it would very likely be accepted. Once we had static key paths working, key path-based dynamic member lookup for static members would most likely fall out of the implementation naturally.

22 Likes

+1 to this idea, I don't see why they wouldn't be supported.

6 Likes

Has there been any progress on this, and if so, where can I follow it? I keep running into the Key path cannot refer to static member issue and would really benefit from being able to refer to static members via key paths.

1 Like

No proposal and working implementation has been proposed by any member of the community, after last message from @beccadax.

It looks like we'll have to wait for quite a while.

Maybe we'll have more success if we open an issue on bugs.swift.org. I don't know what it the priority of "take the time to thoroughly study what is missing in order to complete a feature, and perform the necessary triage between a bland feature, and a subtle one that requires a Swift Evolution process" kinds of tickets, but this should be registered somewhere, with an SR number, instead of falling down into oblivion, lost in the depths of the forum.

1 Like

I agree. Would you be willing to create the ticket for this, and refer to it here? I'd very much like to follow any progress on this issue.

Sure, someone has to do it: [SR-15374] Key paths cannot refer to static member · Issue #57696 · apple/swift · GitHub

Please sign in on bugs.swift.org, and vote for this issue. This can't harm.

8 Likes

+1. To allow enum cases to be used as key paths (and used as dynamic members).

4 Likes

I really need that as well.

+1 on this.

3 Likes

Every couple of months I come here, read up on the thread, check the open Github issue and realise I was here in the past and already upvoted it all :melting_face: I have no idea where one would even start with implementing this but if there were pointers I'd probably take a look :pray:

5 Likes

I have opened a pitch to support key paths to static members here and would appreciate everyone's feedback and constructive criticism.

8 Likes