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?