Skip to content

Add code tabs for _tour/abstract-types #2551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 22, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.