From 05559b02db3307756c93764471c30561b99b41cf Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Sat, 17 Sep 2022 19:40:34 +0200 Subject: [PATCH 1/4] Add code tabs for _tour/for-comprehensions --- _tour/generic-classes.md | 58 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/_tour/generic-classes.md b/_tour/generic-classes.md index d883e88115..15215b9d51 100644 --- a/_tour/generic-classes.md +++ b/_tour/generic-classes.md @@ -14,6 +14,9 @@ Generic classes are classes which take a type as a parameter. They are particula ## Defining a generic class Generic classes take a type as a parameter within square brackets `[]`. One convention is to use the letter `A` as type parameter identifier, though any parameter name may be used. + +{% tabs generic-classes-1 class=tabs-scala-version %} +{% tab 'Scala 2' for=generic-classes-1 %} ```scala mdoc class Stack[A] { private var elements: List[A] = Nil @@ -27,6 +30,22 @@ class Stack[A] { } } ``` +{% endtab %} +{% tab 'Scala 3' for=generic-classes-1 %} +```scala +class Stack[A]: + private var elements: List[A] = Nil + def push(x: A): Unit = + elements = x :: elements + def peek: A = elements.head + def pop(): A = + val currentTop = peek + elements = elements.tail + currentTop +``` +{% endtab %} +{% endtabs %} + This implementation of a `Stack` class takes any type `A` as a parameter. This means the underlying list, `var elements: List[A] = Nil`, can only store elements of type `A`. The procedure `def push` only accepts objects of type `A` (note: `elements = x :: elements` reassigns `elements` to a new list created by prepending `x` to the current `elements`). `Nil` here is an empty `List` and is not to be confused with `null`. @@ -34,15 +53,33 @@ This implementation of a `Stack` class takes any type `A` as a parameter. This m ## Usage To use a generic class, put the type in the square brackets in place of `A`. -``` + +{% tabs generic-classes-2 class=tabs-scala-version %} +{% tab 'Scala 2' for=generic-classes-2 %} +```scala mdoc val stack = new Stack[Int] stack.push(1) stack.push(2) println(stack.pop()) // prints 2 println(stack.pop()) // prints 1 ``` -The instance `stack` can only take Ints. However, if the type argument had subtypes, those could be passed in: +{% endtab %} +{% tab 'Scala 3' for=generic-classes-2 %} +```scala +val stack = Stack[Int] +stack.push(1) +stack.push(2) +println(stack.pop()) // prints 2 +println(stack.pop()) // prints 1 ``` +{% endtab %} +{% endtabs %} + +The instance `stack` can only take Ints. However, if the type argument had subtypes, those could be passed in: + +{% tabs generic-classes-3 class=tabs-scala-version %} +{% tab 'Scala 2' for=generic-classes-3 %} +```scala mdoc class Fruit class Apple extends Fruit class Banana extends Fruit @@ -54,6 +91,23 @@ val banana = new Banana stack.push(apple) stack.push(banana) ``` +{% endtab %} +{% tab 'Scala 3' for=generic-classes-3 %} +```scala +class Fruit +class Apple extends Fruit +class Banana extends Fruit + +val stack = Stack[Fruit] +val apple = Apple() +val banana = Banana() + +stack.push(apple) +stack.push(banana) +``` +{% endtab %} +{% endtabs %} + Class `Apple` and `Banana` both extend `Fruit` so we can push instances `apple` and `banana` onto the stack of `Fruit`. _Note: subtyping of generic types is *invariant*. This means that if we have a stack of characters of type `Stack[Char]` then it cannot be used as an integer stack of type `Stack[Int]`. This would be unsound because it would enable us to enter true integers into the character stack. To conclude, `Stack[A]` is only a subtype of `Stack[B]` if and only if `B = A`. Since this can be quite restrictive, Scala offers a [type parameter annotation mechanism](variances.html) to control the subtyping behavior of generic types._ From 5f37c2327dffe80f5469b12ab7dabcd10bf2a887 Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Sat, 17 Sep 2022 19:45:44 +0200 Subject: [PATCH 2/4] Update generic-classes.md --- _tour/generic-classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_tour/generic-classes.md b/_tour/generic-classes.md index 15215b9d51..968849b411 100644 --- a/_tour/generic-classes.md +++ b/_tour/generic-classes.md @@ -56,7 +56,7 @@ To use a generic class, put the type in the square brackets in place of `A`. {% tabs generic-classes-2 class=tabs-scala-version %} {% tab 'Scala 2' for=generic-classes-2 %} -```scala mdoc +```scala mdoc:nest val stack = new Stack[Int] stack.push(1) stack.push(2) From c58abf40d134f60d1eaf692222ba184b60f9351a Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Sat, 17 Sep 2022 19:49:09 +0200 Subject: [PATCH 3/4] Update generic-classes.md --- _tour/generic-classes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_tour/generic-classes.md b/_tour/generic-classes.md index 968849b411..52d3aa7f7f 100644 --- a/_tour/generic-classes.md +++ b/_tour/generic-classes.md @@ -56,7 +56,7 @@ To use a generic class, put the type in the square brackets in place of `A`. {% tabs generic-classes-2 class=tabs-scala-version %} {% tab 'Scala 2' for=generic-classes-2 %} -```scala mdoc:nest +```scala mdoc val stack = new Stack[Int] stack.push(1) stack.push(2) @@ -79,7 +79,7 @@ The instance `stack` can only take Ints. However, if the type argument had subty {% tabs generic-classes-3 class=tabs-scala-version %} {% tab 'Scala 2' for=generic-classes-3 %} -```scala mdoc +```scala mdoc:nest class Fruit class Apple extends Fruit class Banana extends Fruit From d118499d744b7e083e2433cc4e6635954a0c5927 Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Tue, 20 Sep 2022 11:05:15 +0200 Subject: [PATCH 4/4] Update generic-classes.md --- _tour/generic-classes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_tour/generic-classes.md b/_tour/generic-classes.md index 52d3aa7f7f..5dbb8990d8 100644 --- a/_tour/generic-classes.md +++ b/_tour/generic-classes.md @@ -10,6 +10,7 @@ assumed-knowledge: classes unified-types redirect_from: "/tutorials/tour/generic-classes.html" --- + Generic classes are classes which take a type as a parameter. They are particularly useful for collection classes. ## Defining a generic class