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
-**invariant**---the default, written like `Pipeline[T]`
@@ -45,6 +76,22 @@ This means that types like `Pipeline[Item]`, `Pipeline[Buyable]`, and `Pipeline[
45
76
46
77
And rightfully so! Assume the following method that consumes two values of type `Pipeline[Buyable]`, and passes its argument `b` to one of them, based on the price:
Now, recall that we have the following _subtyping relationship_ between our types:
109
+
110
+
{% tabs types-variance-4 %}
111
+
{% tab 'Scala 2 and 3' %}
59
112
```scala
60
113
Book<:Buyable<:Item
61
114
```
115
+
{% endtab %}
116
+
{% endtabs %}
117
+
62
118
We cannot pass a `Pipeline[Book]` to the method `oneOf` because in its implementation, we call `p1` and `p2` with a value of type `Buyable`.
63
119
A `Pipeline[Book]` expects a `Book`, which can potentially cause a runtime error.
64
120
@@ -68,7 +124,6 @@ We cannot pass a `Pipeline[Item]` because calling `process` on it only promises
68
124
In fact, type `Pipeline` needs to be invariant since it uses its type parameter `T`_both_ as an argument _and_ as a return type.
69
125
For the same reason, some types in the Scala collection library---like `Array` or `Set`---are also _invariant_.
70
126
71
-
72
127
### Covariant Types
73
128
In contrast to `Pipeline`, which is invariant, the type `Producer` is marked as **covariant** by prefixing the type parameter with a `+`.
74
129
This is valid, since the type parameter is only used in a _return position_.
@@ -78,33 +133,47 @@ And in fact, this is sound. The type of `Producer[Buyable].make` only promises t
78
133
As a caller of `make`, we will be happy to also accept a `Book`, which is a subtype of `Buyable`---that is, it is _at least_ a `Buyable`.
79
134
80
135
This is illustrated by the following example, where the function `makeTwo` expects a `Producer[Buyable]`:
136
+
137
+
{% tabs types-variance-5 %}
138
+
{% tab 'Scala 2 and 3' %}
81
139
```scala
82
140
defmakeTwo(p: Producer[Buyable]):Int=
83
141
p.make.price + p.make.price
84
142
```
143
+
{% endtab %}
144
+
{% endtabs %}
145
+
85
146
It is perfectly fine to pass a producer for books:
86
-
```
147
+
148
+
{% tabs types-variance-6 %}
149
+
{% tab 'Scala 2 and 3' %}
150
+
```scala
87
151
valbookProducer:Producer[Book] =???
88
152
makeTwo(bookProducer)
89
153
```
90
-
The call to `price` within `makeTwo` is still valid also for books.
154
+
{% endtab %}
155
+
{% endtabs %}
91
156
157
+
The call to `price` within `makeTwo` is still valid also for books.
92
158
93
159
#### Covariant Types for Immutable Containers
94
160
You will encounter covariant types a lot when dealing with immutable containers, like those that can be found in the standard library (such as `List`, `Seq`, `Vector`, etc.).
95
161
96
162
For example, `List` and `Vector` are approximately defined as:
97
163
164
+
{% tabs types-variance-7 %}
165
+
{% tab 'Scala 2 and 3' %}
98
166
```scala
99
167
classList[+A] ...
100
168
classVector[+A] ...
101
169
```
170
+
{% endtab %}
171
+
{% endtabs %}
102
172
103
173
This way, you can use a `List[Book]` where a `List[Buyable]` is expected.
104
174
This also intuitively makes sense: If you are expecting a collection of things that can be bought, it should be fine to give you a collection of books.
105
175
They have an additional ISBN method in our example, but you are free to ignore these additional capabilities.
106
176
107
-
108
177
### Contravariant Types
109
178
In contrast to the type `Producer`, which is marked as covariant, the type `Consumer` is marked as **contravariant** by prefixing the type parameter with a `-`.
110
179
This is valid, since the type parameter is only used in an _argument position_.
@@ -116,20 +185,34 @@ Remember, for type `Producer`, it was the other way around, and we had `Producer
116
185
And in fact, this is sound. The method `Consumer[Item].take` accepts an `Item`.
117
186
As a caller of `take`, we can also supply a `Buyable`, which will be happily accepted by the `Consumer[Item]` since `Buyable` is a subtype of `Item`---that is, it is _at least_ an `Item`.
118
187
119
-
120
188
#### Contravariant Types for Consumers
121
189
Contravariant types are much less common than covariant types.
122
190
As in our example, you can think of them as “consumers.” The most important type that you might come across that is marked contravariant is the one of functions:
0 commit comments