From d4e360690293a92968a32a6d28157400b08f41ad Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Thu, 22 Sep 2022 16:31:38 +0200 Subject: [PATCH] Add code tabs for _tour/abstract-types --- _tour/abstract-type-members.md | 67 +++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/_tour/abstract-type-members.md b/_tour/abstract-type-members.md index ff6a2b3ddd..aef46a52b2 100644 --- a/_tour/abstract-type-members.md +++ b/_tour/abstract-type-members.md @@ -17,14 +17,28 @@ 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 @@ -32,16 +46,28 @@ abstract class SeqBuffer extends Buffer { 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] @@ -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 @@ -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.