19.5. Make Immutable Collections Covariant
Problem
You want to create a collection whose elements can’t be changed (they’re immutable), and want to understand how to specify it.
Solution
You can define a collection of immutable
elements as invariant, but your collection will be much more flexible if
you declare that your type parameter is covariant.
To make a type parameter covariant, declare it with the +
symbol, like [+A]
.
Covariant type parameters are shown in the Scaladoc for immutable
collection classes like List
,
Vector
, and Seq
:
class
List
[
+T
]
class
Vector
[
+A
]
trait
Seq
[
+A
]
By defining the type parameter to be covariant, you create a situation where the collection can be used in a more flexible manner.
To demonstrate this, modify the example from the previous recipe slightly. First, define the class hierarchy:
trait
Animal
{
def
speak
}
class
Dog
(
var
name
:
String
)
extends
Animal
{
def
speak
{
println
(
"Dog says woof"
)
}
}
class
SuperDog
(
name
:
String
)
extends
Dog
(
name
)
{
override
def
speak
{
println
(
"I'm a SuperDog"
)
}
}
Next, define a makeDogsSpeak
method, but instead of accepting a mutable ArrayBuffer[Dog]
as in the previous recipe,
accept an immutable Seq[Dog]
:
def
makeDogsSpeak
(
dogs
:
Seq
[
Dog
])
{
dogs
.
foreach
(
_
.
speak
)
}
As with the ArrayBuffer
in the
previous recipe, you can pass a sequence of type [Dog]
into makeDogsSpeak
without a problem:
// this works
val
dogs
=
Seq
(
new
Dog
(
"Fido"
),
new
Dog
(
"Tanner"
))
makeDogsSpeak
(
dogs
)
However, in this case, you can also pass a Seq[SuperDog]
into ...
Get Scala Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.