Skip to content

Commit f5b7860

Browse files
committed
mentioned consistency between release and debug modes + various minor fixes
1 parent 9b5f9e2 commit f5b7860

File tree

1 file changed

+38
-19
lines changed

1 file changed

+38
-19
lines changed

proposals/NNNN-opt-in-reflection-metadata.md

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,61 @@
99

1010
## Introduction
1111

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.
1313

1414
Swift-evolution thread: [Discussion thread topic for that proposal](https://forums.swift.org/t/pitch-3-opt-in-reflection-metadata/58852)
1515

1616

1717
## Motivation
1818

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:
2020

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).
2323

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.
2727

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.
2940
Others, like SwiftUI, rely on it and won't work correctly if the reflection metadata is missing.
3041
While the former can benefit as well, the main focus of this proposal is on the latter.
3142

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.
3345
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.
3548

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.
3752
This unnecessarily increases the binary size and may simplify reverse-engineering.
3853

3954
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.
4055

4156

4257
## Proposed solution
4358

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.
4560

4661
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.
4762
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.
4863

4964
### Case Study 1:
5065

51-
SwiftUI Framework:
66+
SwiftUI:
5267
```swift
5368
protocol SwiftUI.View: Reflectable {}
5469
class NSHostingView<Content> where Content : View {
@@ -121,13 +136,13 @@ We also propose to deprecate the compiler's options that can lead to missing ref
121136
### Stdlib behavior changes
122137

123138
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.
125140
If the presence of reflection metadata is mandatory, the requirement on Reflectable protocol should be expressed in the signatures of calling functions.
126141

127142

128143
## Detailed design
129144

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.
131146

132147
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.
133148

@@ -145,11 +160,15 @@ consume(Bar())
145160

146161
### Changes for debugging
147162

148-
Since Reflection metadata might be used by the debugger, we propose to always keep that metadata if full emission of debugging information is enabled (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 is enabled (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.
149167

150168
### Changes in flags
151169

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 default in 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 default in Swift 6.
153172

154173
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.
155174

@@ -220,8 +239,8 @@ It was also considered to use an attribute `@reflectable` on nominal type declar
220239
## Future directions
221240

222241
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.
224243

225244
## Acknowledgments
226245

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

Comments
 (0)