Skip to content

Commit ba907e5

Browse files
authored
Add discussion of 'some' on parameter types [SE-0341] (#350)
Fixes: rdar://143326925
2 parents 88ea77e + bfd1d8f commit ba907e5

File tree

3 files changed

+114
-4
lines changed

3 files changed

+114
-4
lines changed

TSPL.docc/LanguageGuide/Generics.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,21 @@ However, when there isn't a meaningful relationship between them,
286286
it's traditional to name them using single letters such as `T`, `U`, and `V`,
287287
such as `T` in the `swapTwoValues(_:_:)` function above.
288288

289-
> Note: Always give type parameters upper camel case names
290-
> (such as `T` and `MyTypeParameter`)
291-
> to indicate that they're a placeholder for a *type*, not a value.
289+
Use upper camel case names for type parameters,
290+
like `T` and `MyTypeParameter`,
291+
to indicate that they're a placeholder for a *type*, not a value.
292+
293+
> Note:
294+
> If you don't need to name a type parameter
295+
> and its generic type constraints are simple,
296+
> there's an alternate, lightweight syntax you can use instead,
297+
> as described in <doc:OpaqueTypes#Opaque-Parameter-Types>.
298+
<!--
299+
Comparison between this syntax and the lightweight syntax
300+
is in the Opaque Types chapter, not here ---
301+
the reader hasn't learned about constraints yet,
302+
so it wouldn't make sense to list what is/isn't supported.
303+
-->
292304

293305
## Generic Types
294306

TSPL.docc/LanguageGuide/OpaqueTypes.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,67 @@ which means that the type of `twelve` is also inferred to be `Int`.
921921
}
922922
-->
923923

924+
925+
## Opaque Parameter Types
926+
927+
In addition to writing `some` to return an opaque type,
928+
you can also write `some` in the type for a parameter
929+
to a function, subscript, or initializer.
930+
However, when you write `some` in a parameter type
931+
that's just a shorter syntax for generics, not an opaque type.
932+
For example,
933+
both of the functions below are equivalent:
934+
935+
```swift
936+
func drawTwiceGeneric<SomeShape: Shape>(_ shape: SomeShape) -> String {
937+
let drawn = shape.draw()
938+
return drawn + "\n" + drawn
939+
}
940+
941+
func drawTwiceSome(_ shape: some Shape) -> String {
942+
let drawn = shape.draw()
943+
return drawn + "\n" + drawn
944+
}
945+
```
946+
947+
The `drawTwiceGeneric(_:)` function
948+
declares a generic type parameter named `SomeShape`,
949+
with a constraint that requires `SomeShape` to conform to the `Shape` protocol.
950+
The `drawTwiceSome(_:)` function
951+
uses the type `some Shape` for its argument.
952+
This creates a new, unnamed generic type parameter for the function
953+
with a constraint that requires the type to conform to the `Shape` protocol.
954+
Because the generic type doesn't have a name,
955+
you can't refer to that type elsewhere in the function.
956+
957+
If you write `some` before more than one parameter's type,
958+
each of the generic types are independent.
959+
For example:
960+
961+
```swift
962+
func combine(shape s1: some Shape, with s2: some Shape) -> String {
963+
return s1.draw() + "\n" + s2.draw()
964+
}
965+
966+
combine(smallTriangle, trapezoid)
967+
```
968+
969+
In the `combine(shape:with:)` function,
970+
the types of the first and second parameter
971+
must both conform to the `Shape` protocol,
972+
but there's no constraint that requires them to be the same type.
973+
When you call `combine(shape:with)`,
974+
you can pass two different shapes ---
975+
in this case, one triangle and one trapezoid.
976+
977+
Unlike the syntax for named generic type parameters,
978+
described in <docc:Generics> chapter,
979+
this lightweight syntax can't include
980+
a generic `where` clause or any same-type (`==`) constraints.
981+
In addition,
982+
using the lightweight syntax for very complex constraints
983+
can be hard to read.
984+
924985
<!--
925986
This source file is part of the Swift.org open source project
926987

TSPL.docc/ReferenceManual/Types.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,8 @@ that conforms to a protocol or protocol composition,
864864
without specifying the underlying concrete type.
865865

866866
Opaque types appear as the return type of a function or subscript,
867-
or the type of a property.
867+
as the type of a parameter to a function, subscript, or initializer,
868+
or as the type of a property.
868869
Opaque types can't appear as part of a tuple type or a generic type,
869870
such as the element type of an array or the wrapped type of an optional.
870871

@@ -909,6 +910,42 @@ that are part of the function's generic type parameters.
909910
For example, a function `someFunction<T>()`
910911
could return a value of type `T` or `Dictionary<String, T>`.
911912

913+
Writing an opaque type for a parameter
914+
is syntactic sugar for using a generic type,
915+
without specifying a name for the generic type parameter.
916+
The implicit generic type parameter has a constraint
917+
that requires it to conform to the protocol named in the opaque type.
918+
If you write multiple opaque types,
919+
each one makes its own generic type parameter.
920+
For example, the following declarations are equivalent:
921+
922+
```swift
923+
func someFunction(x: some MyProtocol, y: some MyProtocol) { }
924+
func someFunction<T1: MyProtocol, T2: MyProtocol>(x: T1, y: T2) { }
925+
```
926+
927+
In the second declaration,
928+
because the generic type parameters `T1` and `T2` have names,
929+
you can refer use these types elsewhere in the code.
930+
In contrast,
931+
the generic type parameters in the first declaration
932+
don't have names and can't be referenced in other code.
933+
934+
You can't use an opaque type in the type of a variadic parameter.
935+
936+
You can't use an opaque type
937+
as a parameter to a function type being returned,
938+
or as a parameter in a parameter type that's a function type.
939+
In these positions,
940+
the function's caller would have to construct a value
941+
of that unknown type.
942+
943+
```swift
944+
protocol MyProtocol { }
945+
func badFunction() -> (some MyProtocol) -> Void { } // Error
946+
func anotherBadFunction(callback: (some MyProtocol) -> Void) { } // Error
947+
```
948+
912949
> Grammar of an opaque type:
913950
>
914951
> *opaque-type***`some`** *type*

0 commit comments

Comments
 (0)