Skip to content

Commit 6e5a9ce

Browse files
committed
Rewrote abstract types section of tour
1 parent 1a5aabb commit 6e5a9ce

File tree

1 file changed

+29
-34
lines changed

1 file changed

+29
-34
lines changed

tutorials/tour/_posts/2017-02-13-abstract-types.md

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,70 +9,65 @@ categories: tour
99
num: 23
1010
next-page: compound-types
1111
previous-page: inner-classes
12+
prerequisite-knowledge: variance, upper-type-bound
1213
---
1314

14-
In Scala, classes are parameterized with values (the constructor parameters) and with types (if classes are [generic](generic-classes.html)). For reasons of regularity, it is not only possible to have values as object members; types along with values are members of objects. Furthermore, both forms of members can be concrete and abstract.
15-
Here is an example which defines both a deferred value definition and an abstract type definition as members of [class](traits.html) `Buffer`.
16-
15+
Traits and abstract classes can have an abstract type member. This means that the concrete implementations define the actual type. Here's an example:
16+
1717
```tut
1818
trait Buffer {
1919
type T
2020
val element: T
2121
}
2222
```
23-
24-
*Abstract types* are types whose identity is not precisely known. In the example above, we only know that each object of class `Buffer` has a type member `T`, but the definition of class `Buffer` does not reveal to what concrete type the member type `T` corresponds. Like value definitions, we can override type definitions in subclasses. This allows us to reveal more information about an abstract type by tightening the type bound (which describes possible concrete instantiations of the abstract type).
23+
Here we have defined an abstract `type T`. It is used to describe the type of `element`. We can extend this trait in an abstract class, adding an upper-type-bound to `T` to make it more specific.
2524

26-
In the following program we derive a class `SeqBuffer` which allows us to store only sequences in the buffer by stating that type `T` has to be a subtype of `Seq[U]` for a new abstract type `U`:
27-
2825
```tut
2926
abstract class SeqBuffer extends Buffer {
3027
type U
3128
type T <: Seq[U]
3229
def length = element.length
3330
}
3431
```
35-
32+
Notice how we can use yet another abstract `type U` as an upper-type-bound. This `class SeqBuffer` allows us to store only sequences in the buffer by stating that type `T` has to be a subtype of `Seq[U]` for a new abstract type `U`.
33+
3634
Traits or [classes](classes.html) with abstract type members are often used in combination with anonymous class instantiations. To illustrate this, we now look at a program which deals with a sequence buffer that refers to a list of integers:
37-
35+
3836
```tut
3937
abstract class IntSeqBuffer extends SeqBuffer {
4038
type U = Int
4139
}
4240
43-
object AbstractTypeTest1 extends App {
44-
def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
45-
new IntSeqBuffer {
46-
type T = List[U]
47-
val element = List(elem1, elem2)
48-
}
49-
val buf = newIntSeqBuf(7, 8)
50-
println("length = " + buf.length)
51-
println("content = " + buf.element)
52-
}
41+
42+
def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
43+
new IntSeqBuffer {
44+
type T = List[U]
45+
val element = List(elem1, elem2)
46+
}
47+
val buf = newIntSeqBuf(7, 8)
48+
println("length = " + buf.length)
49+
println("content = " + buf.element)
5350
```
54-
55-
The return type of method `newIntSeqBuf` refers to a specialization of trait `Buffer` in which type `U` is now equivalent to `Int`. We have a similar type alias in the anonymous class instantiation within the body of method `newIntSeqBuf`. Here we create a new instance of `IntSeqBuffer` in which type `T` refers to `List[Int]`.
51+
Here the factory `newIntSeqBuf` uses an anonymous class implementation of `IntSeqBuf` (i.e. `new IntSeqBuffer`), setting `type T` to a `List[Int]`.
52+
53+
It is also possible to turn abstract type members into type parameters of classes and vice versa. Here is a version of the code above which only uses type parameters:
5654

57-
Please note that it is often possible to turn abstract type members into type parameters of classes and vice versa. Here is a version of the code above which only uses type parameters:
58-
5955
```tut
6056
abstract class Buffer[+T] {
6157
val element: T
6258
}
6359
abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] {
6460
def length = element.length
6561
}
66-
object AbstractTypeTest2 extends App {
67-
def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
68-
new SeqBuffer[Int, List[Int]] {
69-
val element = List(e1, e2)
70-
}
71-
val buf = newIntSeqBuf(7, 8)
72-
println("length = " + buf.length)
73-
println("content = " + buf.element)
74-
}
62+
63+
def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
64+
new SeqBuffer[Int, List[Int]] {
65+
val element = List(e1, e2)
66+
}
67+
68+
val buf = newIntSeqBuf(7, 8)
69+
println("length = " + buf.length)
70+
println("content = " + buf.element)
7571
```
76-
77-
Note that we have to use [variance annotations](variances.html) here; otherwise we would not be able to hide the concrete sequence implementation type of the object returned from method `newIntSeqBuf`. Furthermore, there are cases where it is not possible to replace abstract types with type parameters.
7872

73+
Note that we have to use [variance annotations](variances.html) here (`+T <: Seq[U]`) in order to hide the concrete sequence implementation type of the object returned from method `newIntSeqBuf`. Furthermore, there are cases where it is not possible to replace abstract types with type parameters.

0 commit comments

Comments
 (0)