Skip to content

Add code tabs for collections-2.13/introduction, overview and trait-iterable #2571

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 9 commits into from
Oct 4, 2022
12 changes: 9 additions & 3 deletions _overviews/collections-2.13/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ permalink: /overviews/collections-2.13/:title.html
---

The collections framework is the heart of the Scala 2.13 standard
library. It provides a common, uniform, and all-encompassing
library, also used in Scala 3.x. It provides a common, uniform, and all-encompassing
framework for collection types. This framework enables you to work
with data in memory at a high level, with the basic building blocks of
a program being whole collections, instead of individual elements.
Expand Down Expand Up @@ -70,12 +70,18 @@ for arrays.
**Example:** Here's one line of code that demonstrates many of the
advantages of Scala's collections.

val (minors, adults) = people partition (_.age < 18)
{% tabs introduction_1 %}
{% tab 'Scala 2 and 3' for=introduction_1 %}
```
val (minors, adults) = people partition (_.age < 18)
```
{% endtab %}
{% endtabs %}

It's immediately clear what this operation does: It partitions a
collection of `people` into `minors` and `adults` depending on
their age. Because the `partition` method is defined in the root
collection type `TraversableLike`, this code works for any kind of
collection type `IterableOps`, this code works for any kind of
collection, including arrays. The resulting `minors` and `adults`
collections will be of the same type as the `people` collection.

Expand Down
70 changes: 50 additions & 20 deletions _overviews/collections-2.13/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ permalink: /overviews/collections-2.13/:title.html
---

Scala collections systematically distinguish between mutable and
immutable collections. A _mutable_ collection can be updated or
immutable collections. A _mutable_ collection can be updated, reduced or
extended in place. This means you can change, add, or remove elements
of a collection as a side effect. _Immutable_ collections, by
contrast, never change. You have still operations that simulate
Expand Down Expand Up @@ -43,7 +43,7 @@ A collection in package `scala.collection` can be either mutable or
immutable. For instance, [collection.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/IndexedSeq.html)
is a superclass of both [collection.immutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/IndexedSeq.html)
and
[collection.mutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/IndexedSeq.html)
[collection.mutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/IndexedSeq.html).
Generally, the root collections in
package `scala.collection` support transformation operations
affecting the whole collection, the immutable
Expand Down Expand Up @@ -73,7 +73,13 @@ A useful convention if you want to use both mutable and immutable
versions of collections is to import just the package
`collection.mutable`.

import scala.collection.mutable
{% tabs overview_1 %}
{% tab 'Scala 2 and 3' for=overview_1 %}
```scala mdoc
import scala.collection.mutable
```
{% endtab %}
{% endtabs %}

Then a word like `Set` without a prefix still refers to an immutable collection,
whereas `mutable.Set` refers to the mutable counterpart.
Expand All @@ -86,10 +92,16 @@ aliases in the `scala` package, so you can use them by their simple
names without needing an import. An example is the `List` type, which
can be accessed alternatively as

scala.collection.immutable.List // that's where it is defined
scala.List // via the alias in the scala package
List // because scala._
// is always automatically imported
{% tabs overview_2 %}
{% tab 'Scala 2 and 3' for=overview_2 %}
```scala mdoc
scala.collection.immutable.List // that's where it is defined
scala.List // via the alias in the scala package
List // because scala._
// is always automatically imported
```
{% endtab %}
{% endtabs %}

Other types aliased are
[Iterable](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterable.html), [Seq](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Seq.html), [IndexedSeq](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/IndexedSeq.html), [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html), [LazyList](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/LazyList.html), [Vector](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Vector.html), [StringBuilder](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/StringBuilder.html), and [Range](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Range.html).
Expand All @@ -116,27 +128,45 @@ Legend:

The most important collection classes are shown in the figures above. There is quite a bit of commonality shared by all these classes. For instance, every kind of collection can be created by the same uniform syntax, writing the collection class name followed by its elements:

Iterable("x", "y", "z")
Map("x" -> 24, "y" -> 25, "z" -> 26)
Set(Color.red, Color.green, Color.blue)
SortedSet("hello", "world")
Buffer(x, y, z)
IndexedSeq(1.0, 2.0)
LinearSeq(a, b, c)
{% tabs overview_3 %}
{% tab 'Scala 2 and 3' for=overview_3 %}
```scala
Iterable("x", "y", "z")
Map("x" -> 24, "y" -> 25, "z" -> 26)
Set(Color.red, Color.green, Color.blue)
SortedSet("hello", "world")
Buffer(x, y, z)
IndexedSeq(1.0, 2.0)
LinearSeq(a, b, c)
```
{% endtab %}
{% endtabs %}

The same principle also applies for specific collection implementations, such as:

List(1, 2, 3)
HashMap("x" -> 24, "y" -> 25, "z" -> 26)
{% tabs overview_4 %}
{% tab 'Scala 2 and 3' for=overview_4 %}
```scala
List(1, 2, 3)
HashMap("x" -> 24, "y" -> 25, "z" -> 26)
```
{% endtab %}
{% endtabs %}

All these collections get displayed with `toString` in the same way they are written above.

All collections support the API provided by `Iterable`, but specialize types wherever this makes sense. For instance the `map` method in class `Iterable` returns another `Iterable` as its result. But this result type is overridden in subclasses. For instance, calling `map` on a `List` yields again a `List`, calling it on a `Set` yields again a `Set` and so on.

scala> List(1, 2, 3) map (_ + 1)
res0: List[Int] = List(2, 3, 4)
scala> Set(1, 2, 3) map (_ * 2)
res0: Set[Int] = Set(2, 4, 6)
{% tabs overview_5 %}
{% tab 'Scala 2 and 3' for=overview_5 %}
```
scala> List(1, 2, 3) map (_ + 1)
res0: List[Int] = List(2, 3, 4)
scala> Set(1, 2, 3) map (_ * 2)
res0: Set[Int] = Set(2, 4, 6)
```
{% endtab %}
{% endtabs %}

This behavior which is implemented everywhere in the collections libraries is called the _uniform return type principle_.

Expand Down
2 changes: 1 addition & 1 deletion _overviews/collections-2.13/seqs.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The [Seq](https://www.scala-lang.org/api/current/scala/collection/Seq.html) trai

The operations on sequences, summarized in the table below, fall into the following categories:

* **Indexing and length** operations `apply`, `isDefinedAt`, `length`, `indices`, and `lengthCompare`. For a `Seq`, the `apply` operation means indexing; hence a sequence of type `Seq[T]` is a partial function that takes an `Int` argument (an index) and which yields a sequence element of type `T`. In other words `Seq[T]` extends `PartialFunction[Int, T]`. The elements of a sequence are indexed from zero up to the `length` of the sequence minus one. The `length` method on sequences is an alias of the `size` method of general collections. The `lengthCompare` method allows you to compare the lengths of a sequences with an Int even if the sequences has infinite length.
* **Indexing and length** operations `apply`, `isDefinedAt`, `length`, `indices`, and `lengthCompare`. For a `Seq`, the `apply` operation means indexing; hence a sequence of type `Seq[T]` is a partial function that takes an `Int` argument (an index) and which yields a sequence element of type `T`. In other words `Seq[T]` extends `PartialFunction[Int, T]`. The elements of a sequence are indexed from zero up to the `length` of the sequence minus one. The `length` method on sequences is an alias of the `size` method of general collections. The `lengthCompare` method allows you to compare the lengths of a sequences with an Int or with an `Iterable` even if the sequences has infinite length.
* **Index search operations** `indexOf`, `lastIndexOf`, `indexOfSlice`, `lastIndexOfSlice`, `indexWhere`, `lastIndexWhere`, `segmentLength`, which return the index of an element equal to a given value or matching some predicate.
* **Addition operations** `prepended`, `prependedAll`, `appended`, `appendedAll`, `padTo`, which return new sequences obtained by adding elements at the front or the end of a sequence.
* **Update operations** `updated`, `patch`, which return a new sequence obtained by replacing some elements of the original sequence.
Expand Down
48 changes: 30 additions & 18 deletions _overviews/collections-2.13/trait-iterable.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ permalink: /overviews/collections-2.13/:title.html

At the top of the collection hierarchy is trait `Iterable`. All methods in this trait are defined in terms of an abstract method, `iterator`, which yields the collection's elements one by one.

def iterator: Iterator[A]
{% tabs trait-iterable_1 %}
{% tab 'Scala 2 and 3' for=trait-iterable_1 %}
```scala
def iterator: Iterator[A]
```
{% endtab %}
{% endtabs %}

Collection classes that implement `Iterable` just need to define this method; all other methods can be inherited from `Iterable`.

Expand All @@ -31,27 +37,33 @@ Collection classes that implement `Iterable` just need to define this method; al
* **Element tests** `exists`, `forall`, `count` which test collection elements with a given predicate.
* **Folds** `foldLeft`, `foldRight`, `reduceLeft`, `reduceRight` which apply a binary operation to successive elements.
* **Specific folds** `sum`, `product`, `min`, `max`, which work on collections of specific types (numeric or comparable).
* **String** operations `mkString`, `addString`, `className`, which give alternative ways of converting a collection to a string.
* **String** operations `mkString`, `addString`, and the protected `className`, which give alternative ways of converting a collection to a string.
* **View** operation: A view is a collection that's evaluated lazily. You'll learn more about views in [later]({% link _overviews/collections-2.13/views.md %}).

Two more methods exist in `Iterable` that return iterators: `grouped` and `sliding`. These iterators, however, do not return single elements but whole subsequences of elements of the original collection. The maximal size of these subsequences is given as an argument to these methods. The `grouped` method returns its elements in "chunked" increments, where `sliding` yields a sliding "window" over the elements. The difference between the two should become clear by looking at the following REPL interaction:

scala> val xs = List(1, 2, 3, 4, 5)
xs: List[Int] = List(1, 2, 3, 4, 5)
scala> val git = xs grouped 3
git: Iterator[List[Int]] = non-empty iterator
scala> git.next()
res3: List[Int] = List(1, 2, 3)
scala> git.next()
res4: List[Int] = List(4, 5)
scala> val sit = xs sliding 3
sit: Iterator[List[Int]] = non-empty iterator
scala> sit.next()
res5: List[Int] = List(1, 2, 3)
scala> sit.next()
res6: List[Int] = List(2, 3, 4)
scala> sit.next()
res7: List[Int] = List(3, 4, 5)
{% tabs trait-iterable_2 %}
{% tab 'Scala 2 and 3' for=trait-iterable_2 %}
```
scala> val xs = List(1, 2, 3, 4, 5)
xs: List[Int] = List(1, 2, 3, 4, 5)
scala> val git = xs grouped 3
git: Iterator[List[Int]] = non-empty iterator
scala> git.next()
res3: List[Int] = List(1, 2, 3)
scala> git.next()
res4: List[Int] = List(4, 5)
scala> val sit = xs sliding 3
sit: Iterator[List[Int]] = non-empty iterator
scala> sit.next()
res5: List[Int] = List(1, 2, 3)
scala> sit.next()
res6: List[Int] = List(2, 3, 4)
scala> sit.next()
res7: List[Int] = List(3, 4, 5)
```
{% endtab %}
{% endtabs %}

### Operations in Class Iterable ###

Expand Down