Skip to content

Commit 76a0028

Browse files
authored
Merge pull request #2420 from amritpan/metatype-kp
[SE-0438] Metatype Keypaths
2 parents c6ea83d + 555e4ce commit 76a0028

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

proposals/0438-metatype-keypath.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Metatype Keypaths
2+
3+
* Proposal: [SE-0438](0438-metatype-keypath.md)
4+
* Authors: [Amritpan Kaur](https://github.com/amritpan), [Pavel Yaskevich](https://github.com/xedin)
5+
* Review Manager: [Joe Groff](https://github.com/jckarter)
6+
* Status: **Active review (May 30th...June 13th, 2024)**
7+
* Implementation: [apple/swift#73242](https://github.com/apple/swift/pull/73242)
8+
* Review: ([Pitch](https://forums.swift.org/t/pitch-metatype-keypaths/70767))
9+
10+
## Introduction
11+
12+
Key path expressions access properties dynamically. They are declared with a concrete root type and one or more key path components that define a path to a resulting value via the type’s properties, subscripts, optional-chaining expressions, forced unwrapped expressions, or self. This proposal expands key path expression access to include static properties of a type, i.e., metatype keypaths.
13+
14+
## Motivation
15+
16+
Metatype keypaths were briefly explored in the pitch for [SE-0254](https://forums.swift.org/t/pitch-static-and-class-subscripts/21850) and the [proposal](https://github.com/apple/swift-evolution/blob/main/proposals/0254-static-subscripts.md#metatype-key-paths) later recommended them as a future direction. Allowing key path expressions to directly refer to static properties has also been discussed on the Swift Forums for database lookups when used [in conjunction with @dynamicMemberLookup](https://forums.swift.org/t/dynamic-key-path-member-lookup-cannot-refer-to-static-member/30212) and as a way to avoid verbose hacks like [referring to a static property through another computed property](https://forums.swift.org/t/key-path-cannot-refer-to-static-member/28055). Supporting metatype keypaths in the Swift language will address these challenges and improve language semantics.
17+
18+
## Proposed solution
19+
20+
We propose to allow keypath expressions to define a reference to static properties. The following usage, which currently generates a compiler error, will be allowed as valid Swift code.
21+
22+
```
23+
struct Bee {
24+
static let name = "honeybee"
25+
}
26+
27+
let kp = \Bee.Type.name
28+
```
29+
30+
## Detailed design
31+
32+
### Metatype syntax
33+
34+
Keypath expressions where the first component refers to a static property will include `.Type` on their root types stated in the key path contextual type or in the key path literal. For example:
35+
36+
```
37+
struct Bee {
38+
static let name = "honeybee"
39+
}
40+
41+
let kpWithContextualType: KeyPath<Bee.Type, String> = \.name // key path contextual root type of Bee.Type
42+
let kpWithLiteral = \Bee.Type.name // key path literal \Bee.Type
43+
```
44+
45+
Attempting to write the above metatype keypath without including `.Type will trigger an error diagnostic:
46+
47+
```
48+
let kpWithLiteral = \Bee.name // error: static member 'name' cannot be used on instance of type 'Bee'
49+
```
50+
51+
Keypath expressions where the component referencing a static property is not the first component do not require `.Type`:
52+
```
53+
struct Species {
54+
static let isNative = true
55+
}
56+
57+
struct Wasp {
58+
var species: Species.Type {Species.self}
59+
}
60+
61+
let kpSecondComponentIsStatic = \Wasp.species.isNative
62+
```
63+
### Access semantics
64+
65+
Immutable static properties will form the read-only keypaths just like immutable instance properties.
66+
```
67+
struct Tip {
68+
static let isIncluded = True
69+
let isVoluntary = False
70+
}
71+
72+
let kpStaticImmutable: KeyPath<Tip.Type, Bool> = \.isIncluded
73+
let kpInstanceImmutable: KeyPath<Tip, Bool> = \.isVoluntary
74+
```
75+
However, unlike instance members, keypaths to mutable static properties will always conform to `ReferenceWritableKeyPath` because metatypes are reference types.
76+
```
77+
struct Tip {
78+
static var total = 0
79+
var flatRate = 20
80+
}
81+
82+
let kpStaticMutable: ReferenceWriteableKeyPath<Tip.Type, Int> = \.total
83+
let kpInstanceMutable: WriteableKeyPath<Tip, Int> = \.flatRate
84+
```
85+
## Effect on source compatibility
86+
87+
This feature breaks source compatibility for key path expressions that reference static properties after subscript overloads. For example, the compiler cannot differentiate between subscript keypath components by return type in the following:
88+
89+
```
90+
struct S {
91+
static var count: Int { 42 }
92+
}
93+
94+
struct Test {
95+
subscript(x: Int) -> String { "" }
96+
subscript(y: Int) -> S.Type { S.self }
97+
}
98+
99+
let kpViaSubscript = \Test.[42] // fails to typecheck
100+
```
101+
102+
This keypath does not specify a contextual type, without which the key path value type is unknown. To form a keypath to the metatype subscript and return an `Int`, we can specify a contextual type with a value type of `S.Type` and chain the metatype keypath:
103+
104+
```
105+
let kpViaSubscript: KeyPath<Test, S.Type> = \Test.[42]
106+
let kpAppended = kpViaSubscript.appending(path: \.count)
107+
```
108+
109+
## ABI compatibility / Implications on adoption
110+
111+
This feature does not affect ABI compatibility and has no implications on adoption.
112+
113+
## Future directions
114+
115+
### Key Paths to Enum cases
116+
117+
Adding language support for read-only key paths to enum cases has been widely discussed on the [Swift Forums](https://forums.swift.org/t/enum-case-key-paths-an-update/68436) but has been left out of this proposal as this merits a separate discussion around [syntax design and implementation concerns](https://forums.swift.org/t/enum-case-keypaths/60899/32).
118+
119+
Since references to enum cases must be metatypes, extending keypath expressions to include references to metatypes will hopefully bring the Swift language closer to adopting keypaths to enum cases in a future pitch.
120+
121+
## Acknowledgments
122+
123+
Thank you to Joe Groff for providing pivotal feedback on this pitch and its possible implementation and to Becca Royal-Gordon for an insightful discussion around the anticipated hurdles in implementing this feature.

0 commit comments

Comments
 (0)