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/0315-placeholder-types.md
+13-13Lines changed: 13 additions & 13 deletions
Original file line number
Diff line number
Diff line change
@@ -34,19 +34,19 @@ Fortunately, Swift provides several ways for the user to provide type informatio
34
34
* Variable type annotations:
35
35
36
36
```swift
37
-
let losslessStringConverter: (String) ->Double=Double.init
37
+
let losslessStringConverter: (String) ->Double?=Double.init
38
38
```
39
39
40
40
* Type coercion via `as` (seen above):
41
41
42
42
```swift
43
-
let losslessStringConverter =Double.initas (String) ->Double
43
+
let losslessStringConverter =Double.initas (String) ->Double?
44
44
```
45
45
46
46
* Passing type parameters explicitly (e.g., `JSONDecoder` ):
47
47
48
48
```swift
49
-
let dict =JSONDecoder().decode([String:Int].self, from: data)
49
+
let dict =tryJSONDecoder().decode([String:Int].self, from: data)
50
50
```
51
51
52
52
The downside of all of these approaches is that they require the user to write out the *entire* type, even when the compiler only needs guidance on some sub-component of that type. This can become particularly problematic in cases where a complex type that would normally be inferred has to be written out explicitly because some *unrelated* portion of the type signature is required. E.g.,
Now, the type checker has all the information it needs to resolve the reference to `makeValue` : the ultimately resulting `AnyPublisher` must have `Output == Int` , so the result of `setFailureType(to:)` must have `Output == Int` , so the instance of `Just` must have `Output == Int` , so the argument to `Just.init` must have type `Int` , so `makeValue` must refer to the `Int` -returning overload!
139
139
140
-
Note: it is not permitted to specify a type that is _just_ a placeholder—see the relevant subsection in **Future directions** for a dicussion of the considerations. This means that, for example, the following would fail to compile:
140
+
Note: it is not permitted to specify a type that is _just_ a placeholder—see the relevant subsection in **Future directions** for a discussion of the considerations. This means that, for example, the following would fail to compile:
141
141
142
142
```swift
143
143
let percent: _ =100.0// error: placeholders are not allowed as top-level types
@@ -151,7 +151,7 @@ In some cases, placeholders may be expected to conform to certain protocols. E.g
151
151
let dict: [_: String] = [0:"zero", 1:"one", 2:"two"]
152
152
```
153
153
154
-
When examining the storage type for `dict` , the compiler will expect the placeholder key type to conform to `Hashable` . Conservatively, placeholder types are assumed to satisfy all necessary constraints, deferring the verification of these constraints until the checking of the intialization expression.
154
+
When examining the storage type for `dict` , the compiler will expect the placeholder key type to conform to `Hashable` . Conservatively, placeholder types are assumed to satisfy all necessary constraints, deferring the verification of these constraints until the checking of the initialization expression.
155
155
156
156
### Generic parameter inference
157
157
@@ -206,31 +206,31 @@ extension Bar {
206
206
funcfrobnicate() -> Bar {
207
207
returnBar(t: 42, u: 42)
208
208
}
209
-
funcfrobnicate2() -> Bar<_, _> {
209
+
funcfrobnicate2() -> Bar<_, _> {// error
210
210
returnBar(t: 42, u: 42)
211
211
}
212
212
funcfrobnicate3() -> Bar {
213
213
return Bar<_, _>(t: 42, u: 42)
214
214
}
215
-
funcfrobnicate4() -> Bar<_, _> {
215
+
funcfrobnicate4() -> Bar<_, _> {// error
216
216
return Bar<_, _>(t: 42, u: 42)
217
217
}
218
-
funcfrobnicate5() -> Bar<_, U> {
218
+
funcfrobnicate5() -> Bar<_, U> {// error
219
219
returnBar(t: 42, u: 42)
220
220
}
221
221
funcfrobnicate6() -> Bar {
222
222
return Bar<_, U>(t: 42, u: 42)
223
223
}
224
-
funcfrobnicate7() -> Bar<_, _> {
224
+
funcfrobnicate7() -> Bar<_, _> {// error
225
225
return Bar<_, U>(t: 42, u: 42)
226
226
}
227
-
funcfrobnicate8() -> Bar<_, U> {
227
+
funcfrobnicate8() -> Bar<_, U> {// error
228
228
return Bar<_, _>(t: 42, u: 42)
229
229
}
230
230
}
231
231
```
232
232
233
-
Under this proposal, only `frobnicate`, `frobnicate3` and `frobnicate6` would compile without error (`frobnicate1`, of course, compiles without this proposal as well), since all others have placeholders appearing in at least one position in the function signature.
233
+
Under this proposal, only `frobnicate`, `frobnicate3` and `frobnicate6` would compile without error (`frobnicate`, of course, compiles without this proposal as well), since all others have placeholders appearing in at least one position in the function signature.
234
234
235
235
### Dynamic casts
236
236
@@ -326,7 +326,7 @@ An earlier draft of this proposal allowed for the use of placeholders as top-lev
326
326
let x: _ =0.0// type of x is inferred as Double
327
327
```
328
328
329
-
Compared to other uses of this feature, top-level placeholders are clearly of more limited utility. In type annotations (as above), they merely serve as a slightly more explicit way to indicate "this type is inferred," and they are similarly unhelpful in `as` casts. There is *some* use for top-level placeholders in type expression position, particularly when passing a metatype value as a parameter. For instance, Combine's `setFailureType(to:)` operator could be used with a top-level placeholder to make conversions between failure types more lightweight wen necessary:
329
+
Compared to other uses of this feature, top-level placeholders are clearly of more limited utility. In type annotations (as above), they merely serve as a slightly more explicit way to indicate "this type is inferred," and they are similarly unhelpful in `as` casts. There is *some* use for top-level placeholders in type expression position, particularly when passing a metatype value as a parameter. For instance, Combine's `setFailureType(to:)` operator could be used with a top-level placeholder to make conversions between failure types more lightweight when necessary:
330
330
331
331
```swift
332
332
let p: AnyPublisher<Int, Error> = Just<Int>().setFailureType(to: _.self).eraseToAnyPublisher()
However, as Xiaodi Wu points out, allowing placeholders in these positions would have the effect of permitting clients to leave out type names in circumstances where library authors intended the type information to be provided explicitly, such as when using `KeyedDecodingContainer.decode(_:forKey:)`. It is not obviously desirable for users to be able to write, e.g.:
Due to the additional considerations here, the author has opted to leave top-level placeholders as a future direction, which could potentially be considered once there is more real-world usage of placeholder types that could inform the benefits and drawbacks.
0 commit comments