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: _tour/variances.md
+10-10Lines changed: 10 additions & 10 deletions
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,7 @@ previous-page: generic-classes
10
10
redirect_from: "/tutorials/tour/variances.html"
11
11
---
12
12
13
-
Variance is a property of parameterized types that relates the subtyping relationship of parameterized types to the subtyping releationship of its type parameter. Scala supports variance annotations of type parameters of [generic classes](generic-classes.html), to allow them to be covariant, contravariant, or invariant if no annotations are used. The use of variance in the type system allows us to make intuitive connections between complex types.
13
+
Variance lets you control how type parameters behave with regards to subtyping. Scala supports variance annotations of type parameters of [generic classes](generic-classes.html), to allow them to be covariant, contravariant, or invariant if no annotations are used. The use of variance in the type system allows us to make intuitive connections between complex types.
14
14
15
15
```scala mdoc
16
16
classFoo[+A] // A covariant class
@@ -20,7 +20,7 @@ class Baz[A] // An invariant class
20
20
21
21
### Invariance
22
22
23
-
By default, type paramters in scala are invariant: subtyping relationships between the type paramter aren't reflected in the parameterized type. To explore why this works the way it does, we look at a simple parameterized type, the mutable box.
23
+
By default, type parameters in Scala are invariant: subtyping relationships between the type parameters aren't reflected in the parameterized type. To explore why this works the way it does, we look at a simple parameterized type, the mutable box.
24
24
25
25
```scala mdoc
26
26
classBox[A](varcontent:A)
@@ -39,27 +39,27 @@ case class Dog(name: String) extends Animal
39
39
We can say that `Cat` is a subtype of `Animal`, and that `Dog` is also a subtype of `Animal`. That means that the following is well-typed:
40
40
41
41
```scala mdoc
42
-
valmyAnimal:Animal=Cat("felix")
42
+
valmyAnimal:Animal=Cat("Felix")
43
43
```
44
44
45
-
What about boxes? If I have a `Box[Cat]`, is it a subtype of `Box[Animal]`, like `Cat` is a subtype of `Animal`? At first sight, it looks like that may be plausible, but if we try to do that, the compiler will tell us we have an error:
45
+
What about boxes? Is `Box[Cat]` a subtype of `Box[Animal]`, like `Cat` is a subtype of `Animal`? At first sight, it looks like that may be plausible, but if we try to do that, the compiler will tell us we have an error:
46
46
47
47
```scala
48
-
valmyCatBox:Box[Cat] =newBox[Cat](Cat("felix"))
48
+
valmyCatBox:Box[Cat] =newBox[Cat](Cat("Felix"))
49
49
valmyAnimalBox:Box[Animal] = myCatBox // this doesn't compile
50
50
valmyAnimal:Animal= myAnimalBox.content
51
51
```
52
52
53
53
Why could this be a problem? We can get the cat from the box, and it's still an Animal, isn't it? Well, yes. But that's not all we can do. We can also replace the cat in the box with a different animal
54
54
55
55
```scala
56
-
mayAnimalBox.content =Dog("fido")
56
+
mayAnimalBox.content =Dog("Fido")
57
57
```
58
58
59
-
There now is a Dog in the Animal box. That's all fine, you can put Dogs in Animal boxes, because Dogs are Animals. But our Animal Box is a Cat Box! You can't put a Dog in a Cat box. If we could, and then try to get the cat from our catbox, it would turn out to be a dog, breaking type soundness.
59
+
There now is a Dog in the Animal box. That's all fine, you can put Dogs in Animal boxes, because Dogs are Animals. But our Animal Box is a Cat Box! You can't put a Dog in a Cat box. If we could, and then try to get the cat from our Cat Box, it would turn out to be a dog, breaking type soundness.
60
60
61
61
```scala
62
-
valmyCat:Cat= myCatBox.content //myCat would be fido the dog!
62
+
valmyCat:Cat= myCatBox.content //myCat would be Fido the dog!
63
63
```
64
64
65
65
From this, we have to conclude that `Box[Cat]` and `Box[Animal]` can't have a subtyping relationship, even though `Cat` and `Animal` do.
@@ -100,7 +100,7 @@ printAnimalNames(dogs)
100
100
101
101
### Contravariance
102
102
103
-
We've seen we can accomplish Covariance by making sure that we can't put something in the Covariant type, but only get something out. What if we had the opposite, something you can put something in, but can't take out? This situation arises if we have something like a serializer, that takes values of type A, and converts them to a serialized format.
103
+
We've seen we can accomplish covariance by making sure that we can't put something in the covariant type, but only get something out. What if we had the opposite, something you can put something in, but can't take out? This situation arises if we have something like a serializer, that takes values of type A, and converts them to a serialized format.
104
104
105
105
```scala mdoc
106
106
abstractclassSerializer[-A] {
@@ -122,4 +122,4 @@ More formally, that gives us the reverse relationship: given some `class Contra[
122
122
123
123
Variance is supported in different ways by some languages that are similar to Scala. For example, variance annotations in Scala closely resemble those in C#, where the annotations are added when a class abstraction is defined (declaration-site variance). In Java, however, variance annotations are given by clients when a class abstraction is used (use-site variance).
124
124
125
-
Scalas tendency towards immutable types makes it that covariant and contravariant types are more common than in other languages, since a mutabable generic type can't be covariant or contravariant.
125
+
Scala's tendency towards immutable types makes it that covariant and contravariant types are more common than in other languages, since a mutable generic type must be invariant.
0 commit comments