You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/NNNN-opt-in-reflection-metadata.md
+38-19Lines changed: 38 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,46 +9,61 @@
9
9
10
10
## Introduction
11
11
12
-
This proposal seeks to increase the safety, efficiency and privacy of Swift Reflection Metadata by improving the existing mechanism and providing the opportunity to express a requirement on Reflection Metadata in APIs that consume it.
12
+
This proposal seeks to increase the safety, efficiency, and secrecy of Swift Reflection Metadata by improving the existing mechanism and providing the opportunity to express a requirement on Reflection Metadata in APIs that consume it.
13
13
14
14
Swift-evolution thread: [Discussion thread topic for that proposal](https://forums.swift.org/t/pitch-3-opt-in-reflection-metadata/58852)
15
15
16
16
17
17
## Motivation
18
18
19
-
There are two kinds of Swift metadata emitted by the compiler:
19
+
There are two main kinds of Swift metadata emitted by the compiler:
20
20
21
-
1. Core Metadata (type metadata record, nominal type descriptor, etc).
22
-
2. Reflection metadata (reflection metadata field descriptor).
21
+
1. Core Metadata (type metadata records, nominal type descriptors, etc).
22
+
2. Reflection metadata (reflection metadata field descriptors).
23
23
24
-
Core metadata must constantly be emitted and may only be stripped if provenly not used. (This metadata isn't affected by this proposal.)
25
-
Reflection metadata contains optional information about declarations' fields - their names and references to their types.
26
-
This metadata isn't used by the language's runtime features, and the emission may be skipped if such types aren't passed to reflection-consuming APIs.
24
+
Core metadata must constantly be emitted and may only be stripped if provenly not used. (This kind of metadata isn't affected by this proposal.)
25
+
On the other hand, reflection metadata contains optional information about declaration fields - their names and references to their types.
26
+
The language's runtime features don't use this metadata, and the emission may be skipped if such types aren't passed to reflection-consuming APIs.
27
27
28
-
APIs can use Reflection Metadata differently. Some like `print`, and `dump` will still work with disabled reflection, but the output will be limited.
28
+
29
+
Currently, there is no way to selectively enable the emission of reflectable metadata for a type or understand if an API consumes reflection metadata under the hood.
30
+
Moreover, compiler's flags exist that allow to completely disable emission.
31
+
32
+
A developer has two ways right now - either
33
+
1. To just in case enable Reflection in full.
34
+
2. To try to guess which used APIs consume Reflection, and enable it only for modules that are users of such APIs.
35
+
36
+
Both of those options have flaws. The first one leads to exsessive contribution of reflection metadta to binary size and might affects the secrecy of generated code.
37
+
The second one isn't safe because many APIs are black boxes if the guess is wrong, an app might behave not as expected at runtime.
38
+
39
+
Furthermore, APIs can use Reflection Metadata differently. Some like `print`, `debugPrint`, and `dump` will still work with disabled reflection, but the output will be limited.
29
40
Others, like SwiftUI, rely on it and won't work correctly if the reflection metadata is missing.
30
41
While the former can benefit as well, the main focus of this proposal is on the latter.
31
42
32
-
A developer can mistakenly turn off Reflection Metadata for a Swift module and won't be warned at compile-time if APIs that consume reflection are used by that module. An app with such a module won't behave as expected at runtime which may be challenging to notice and track down such bugs back to Reflection.
43
+
A developer can mistakenly turn off Reflection Metadata for a Swift module and won't be warned at compile-time if APIs that consume reflection are used by that module.
44
+
An app with such a module won't behave as expected at runtime which may be challenging to notice and track down such bugs back to Reflection.
33
45
For instance, SwiftUI implementation uses reflection metadata from user modules to trigger the re-rendering of the view hierarchy when a state has changed.
34
-
If for some reason a user module was compiled with metadata generation disabled, changing the state won't trigger that behavior and will cause inconsistency between state and representation which will make such API less safe since it becomes a runtime issue rather than a compile-time one.
46
+
If for some reason a user module was compiled with metadata generation disabled, changing the state won't trigger that behavior and will cause inconsistency
47
+
between state and representation which will make such API less safe since it becomes a runtime issue rather than a compile-time one.
35
48
36
-
On the other hand, excessive Reflection metadata may be preserved in a binary even if not used, because there is currently no way to statically determine its usage. There was an attempt to limit the amount of unused reflection metadata by improving its stripability by the Dead Code Elimination LLVM pass, but in many cases, it’s still preserved in the binary because it’s referenced by Full Type Metadata which prevents Reflection Metadata from stripping.
49
+
On the other hand, excessive Reflection metadata may be preserved in a binary even if not used, because there is currently no way to statically determine its usage.
50
+
There was an attempt to limit the amount of unused reflection metadata by improving its stripability by the Dead Code Elimination LLVM pass, but in many cases,
51
+
it’s still preserved in the binary because it’s referenced by Full Type Metadata which prevents Reflection Metadata from stripping.
37
52
This unnecessarily increases the binary size and may simplify reverse-engineering.
38
53
39
54
Introducing a static compilation check can help to solve both of mentioned issues by adding to the language a way to express the requirement to have Reflection metadata at runtime.
40
55
41
56
42
57
## Proposed solution
43
58
44
-
Teaching the Type-checker and IRGen to ensure Reflection metadata is preserved in a binary if reflection-consuming APIs are used, will help to move the issue from runtime to compile time.
59
+
Teaching the Type-checker and IRGen to ensure Reflection metadata is preserved in a binary if reflection-consuming APIs are used, will help to move the problem from runtime to compile time.
45
60
46
61
To achieve that, a new marker protocol `Reflectable` will be introduced. Firstly, APIs developers will gain an opportunity to express a dependency on Reflection Metadata through a generic requirement of their functions, which will make such APIs safer.
47
62
Secondly, during IRGen, the compiler will be able to selectively emit Reflection symbols for the types that explicitly conform to the `Reflectable` protocol, which will reduce the overhead from reflection symbols for cases when reflection is emitted but not consumed.
48
63
49
64
### Case Study 1:
50
65
51
-
SwiftUI Framework:
66
+
SwiftUI:
52
67
```swift
53
68
protocolSwiftUI.View: Reflectable {}
54
69
classNSHostingView<Content> where Content :View {
@@ -121,13 +136,13 @@ We also propose to deprecate the compiler's options that can lead to missing ref
121
136
### Stdlib behavior changes
122
137
123
138
In Swift `Mirror(reflecting:)` is the only official way to access Reflection metadata, all other APIs are using it under the hood.
124
-
We intentionally do not propose adding a Reflectable constraint on Mirror type, because it would impose restrictions on those developers who still don't want to require it.
139
+
We intentionally do not propose adding a Reflectable constraint on Mirror type, because it would impose restrictions on those developers who still don't want to require it and consume Reflection optionally.
125
140
If the presence of reflection metadata is mandatory, the requirement on Reflectable protocol should be expressed in the signatures of calling functions.
126
141
127
142
128
143
## Detailed design
129
144
130
-
To decide when to emit reflection metadata IRGen will check the conformance of a type to the `Reflectable` protocol and if the type conforms, IRGen will emit reflection.
145
+
To decide when to emit reflection metadata IRGen will check the conformance of a type to the `Reflectable` protocol and if the type conforms, IRGen will emit reflection symbols.
131
146
132
147
Conformance to Reflectable should be only allowed at type declarations level, to avoid confusing behavior, when a developer adds conformance on an imported from another module type that doesn't have reflection enabled.
133
148
@@ -145,11 +160,15 @@ consume(Bar())
145
160
146
161
### Changes for debugging
147
162
148
-
Since Reflection metadata might be used by the debugger, we propose to always keep that metadata if full emission of debugging information isenabled (with`-gdwarf-types` or `-g` flags).
163
+
Since Reflection metadata might be used by the debugger, we propose to always keep that metadata
164
+
if full emission of debugging information isenabled (with `-gdwarf-types` or `-g` flags).
165
+
However, such Reflection metadata won't be accessible through the nominal type descriptor
166
+
which will allow to avoid inconsistencies between APIs' outputs in Release and Debug modes.
149
167
150
168
### Changes in flags
151
169
152
-
To handle behavior change between Swift pre-6 and 6, we can introduce a new upcoming feature, which will allow to enable Opt-In mode explicitly for pre-6 Swift with `-enable-upcoming-feature OptInReflection` and will set this mode by defaultin Swift 6.
170
+
To handle behavior change between Swift pre-6 and 6, we can introduce a new upcoming feature,
171
+
which will allow to enable Opt-In mode explicitly for Swift pre-6 with `-enable-upcoming-feature OptInReflection` and will set this mode by defaultin Swift 6.
153
172
154
173
A new flag `-enable-full-reflection-metadata` will also have to be introduced to allow developers to enable reflection in full if they desire in Swift 6 and later.
155
174
@@ -220,8 +239,8 @@ It was also considered to use an attribute `@reflectable` on nominal type declar
220
239
## Future directions
221
240
222
241
Currently, there is only one kind of Reflection Metadata - Field Descriptor Metadata. In the future, it is possible that other kinds will be added (e.g methods, computed properties, etc) `Reflectable` should be able to cover all of them.
223
-
242
+
If this proposal is approved, it will become easier and more native to migrate Codable to the usage of Reflection metadata for encoding/decoding logic instead of autogenerating code at compile time.
224
243
225
244
## Acknowledgments
226
245
227
-
Thanks to [Joe Groff](https://github.com/jckarter) for various useful pieces of advice, general help along the journey, and for suggesting several useful features like Reflectable casts!
246
+
Thanks to [Joe Groff](https://github.com/jckarter) for various useful pieces of advice, general help along the way, and for suggesting several useful features like Reflectable casts!
0 commit comments