File: opaque-type-inference.md

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (68 lines) | stat: -rw-r--r-- 3,227 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# Underlying Type Inference for Opaque Result Types

Opaque result types are a useful tool for abstracting the return type of a function or subscript, or type of a property. Although the concrete underlying type of an opaque type is hidden from clients, it is still inferred by the compiler, which enforces certain usage requirements:

- Property declarations with opaque types must have an initializer expression or getter, and functions or subscripts returning opaque types must have at least one `return` statement:

```swift
let x: some Equatable // error: property declares an opaque return type, but has no initializer expression from which to infer an underlying type
let y: some Equatable = 42 // OK
let z: some Equatable { // Also OK
  return "hello, " + "world!"
}

func foo() -> some Equatable { // error: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
  fatalError("Unimplemented")
}

func bar() -> some Equatable { // OK
  fatalError("Unimplemented")
  return 42
}
```

- The underlying type of an opaque type must be unique. In other words, if a function or subscript returns an opaque type, it must return values of the same underlying type from every `return` statement in its body.

```swift
func foo(bar: Bool) -> some Equatable { // error: function declares an opaque return type, but the return statements in its body do not have matching underlying types
  if bar {
    return "hello, world!" // note: return statement has underlying type 'String'
  } else {
    return 1 // note: return statement has underlying type 'Int'
  }
}

func bar(baz: Bool) -> some Equatable { // OK, both branches of the if statement return a value of the same underlying type, Int.
  if baz {
    return 100
  } else {
    return 200
  }
}
```

- Functions returning opaque types may be recursive. However, such functions must have at least one `return` statement that returns a concrete underlying type as opposed to the function's own opaque result type. Additionally, recursive calls may not be used to create an infinitely recursive opaque type.

```swift
func foo(_ x: Int) -> some Equatable { // error: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
  // Not allowed because there aren't any non-recursive returns to infer the underlying type from.
  return foo(x+1)
}

struct EquatableWrapper<T: Equatable>: Equatable { var value: T }
func foo() -> some Equatable { // error: function opaque return type was inferred as 'EquatableWrapper<some Equatable>', which defines the opaque type in terms of itself
  // Not allowed because the use of EquatableWrapper creates an infinitely recursive underlying type: EquatableWrapper<EquatableWrapper<EquatableWrapper<...>>>...>
  return EquatableWrapper(value: foo())
}

func bar(_ x: Int) -> some Equatable { // OK, the underlying type can be inferred from the second return statement.
  if x > 0 {
    return bar(x-1)
  } else {
    return x
  }
}
```

To learn more about opaque result types, see the [Opaque Types](https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html) section of _The Swift Programming Language_.