Skip to content

Commit

Permalink
Merge pull request #2551 from flomebul/abstract-types
Browse files Browse the repository at this point in the history
Add code tabs for _tour/abstract-types
  • Loading branch information
julienrf authored Sep 22, 2022
2 parents de06e87 + d4e3606 commit 534965a
Showing 1 changed file with 66 additions and 1 deletion.
67 changes: 66 additions & 1 deletion _tour/abstract-type-members.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,57 @@ Abstract types, such as traits and abstract classes, can in turn have abstract t
This means that the concrete implementations define the actual types.
Here's an example:

{% tabs abstract-types_1 class=tabs-scala-version %}
{% tab 'Scala 2' for=abstract-types_1 %}
```scala mdoc
trait Buffer {
type T
val element: T
}
```
{% endtab %}
{% tab 'Scala 3' for=abstract-types_1 %}
```scala
trait Buffer:
type T
val element: T
```
{% endtab %}
{% endtabs %}

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.

{% tabs abstract-types_2 class=tabs-scala-version %}
{% tab 'Scala 2' for=abstract-types_2 %}
```scala mdoc
abstract class SeqBuffer extends Buffer {
type U
type T <: Seq[U]
def length = element.length
}
```
{% endtab %}
{% tab 'Scala 3' for=abstract-types_2 %}
```scala
abstract class SeqBuffer extends Buffer:
type U
type T <: Seq[U]
def length = element.length
```
{% endtab %}
{% endtabs %}

Notice how we can use yet another abstract type `U` in the specification of an upper-type-bound for `T`. 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`.

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:

{% tabs abstract-types_3 class=tabs-scala-version %}
{% tab 'Scala 2' for=abstract-types_3 %}
```scala mdoc
abstract class IntSeqBuffer extends SeqBuffer {
type U = Int
}


def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
new IntSeqBuffer {
type T = List[U]
Expand All @@ -51,10 +77,30 @@ val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
```
{% endtab %}
{% tab 'Scala 3' for=abstract-types_3 %}
```scala
abstract class IntSeqBuffer extends SeqBuffer:
type U = Int

def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
new IntSeqBuffer:
type T = List[U]
val element = List(elem1, elem2)

val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
```
{% endtab %}
{% endtabs %}

Here the factory `newIntSeqBuf` uses an anonymous class implementation of `IntSeqBuffer` (i.e. `new IntSeqBuffer`) to set the abstract type `T` to the concrete type `List[Int]`.

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:

{% tabs abstract-types_4 class=tabs-scala-version %}
{% tab 'Scala 2' for=abstract-types_4 %}
```scala mdoc:nest
abstract class Buffer[+T] {
val element: T
Expand All @@ -72,5 +118,24 @@ val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
```
{% endtab %}
{% tab 'Scala 3' for=abstract-types_4 %}
```scala
abstract class Buffer[+T]:
val element: T

abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T]:
def length = element.length

def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] =
new SeqBuffer[Int, List[Int]]:
val element = List(e1, e2)

val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
```
{% endtab %}
{% endtabs %}

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 type members with type parameters.

0 comments on commit 534965a

Please sign in to comment.