diff --git a/_overviews/scala3-book/first-look-at-types.md b/_overviews/scala3-book/first-look-at-types.md
index 26645ea76c..32e24f19b3 100644
--- a/_overviews/scala3-book/first-look-at-types.md
+++ b/_overviews/scala3-book/first-look-at-types.md
@@ -8,7 +8,6 @@ next-page: control-structures
---
-
## All values have a type
In Scala, all values have a type, including numerical values and functions.
@@ -16,7 +15,6 @@ The diagram below illustrates a subset of the type hierarchy.
-
## Scala type hierarchy
`Any` is the supertype of all types, also called the **top type**.
@@ -42,12 +40,18 @@ If Scala is used in the context of a Java runtime environment, `AnyRef` correspo
In statement-based languages, `void` is used for methods that don’t return anything.
If you write methods in Scala that have no return value, such as the following method, `Unit` is used for the same purpose:
+{% tabs unit %}
+{% tab 'Scala 2 and 3' for=unit %}
```scala
def printIt(a: Any): Unit = println(a)
```
+{% endtab %}
+{% endtabs %}
Here’s an example that demonstrates that strings, integers, characters, boolean values, and functions are all instances of `Any` and can be treated just like every other object:
+{% tabs any %}
+{% tab 'Scala 2 and 3' for=any %}
```scala
val list: List[Any] = List(
"a string",
@@ -59,6 +63,8 @@ val list: List[Any] = List(
list.foreach(element => println(element))
```
+{% endtab %}
+{% endtabs %}
The code defines a value `list` of type `List[Any]`.
The list is initialized with elements of various types, but each is an instance of `scala.Any`, so we can add them to the list.
@@ -78,6 +84,8 @@ true
As shown above, Scala’s numeric types extend `AnyVal`, and they’re all full-blown objects.
These examples show how to declare variables of these numeric types:
+{% tabs anyval %}
+{% tab 'Scala 2 and 3' for=anyval %}
```scala
val b: Byte = 1
val i: Int = 1
@@ -86,31 +94,45 @@ val s: Short = 1
val d: Double = 2.0
val f: Float = 3.0
```
+{% endtab %}
+{% endtabs %}
In the first four examples, if you don’t explicitly specify a type, the number `1` will default to an `Int`, so if you want one of the other data types---`Byte`, `Long`, or `Short`---you need to explicitly declare those types, as shown.
Numbers with a decimal (like 2.0) will default to a `Double`, so if you want a `Float` you need to declare a `Float`, as shown in the last example.
Because `Int` and `Double` are the default numeric types, you typically create them without explicitly declaring the data type:
+{% tabs anynum %}
+{% tab 'Scala 2 and 3' for=anynum %}
```scala
val i = 123 // defaults to Int
val x = 1.0 // defaults to Double
```
+{% endtab %}
+{% endtabs %}
In your code you can also append the characters `L`, `D`, and `F` (and their lowercase equivalents) to numbers to specify that they are `Long`, `Double`, or `Float` values:
+{% tabs type-post %}
+{% tab 'Scala 2 and 3' for=type-post %}
```scala
val x = 1_000L // val x: Long = 1000
val y = 2.2D // val y: Double = 2.2
val z = 3.3F // val z: Float = 3.3
```
+{% endtab %}
+{% endtabs %}
Scala also has `String` and `Char` types, which you can generally declare with the implicit form:
+{% tabs type-string %}
+{% tab 'Scala 2 and 3' for=type-string %}
```scala
val s = "Bill"
val c = 'a'
```
+{% endtab %}
+{% endtabs %}
As shown, enclose strings in double-quotes---or triple-quotes for multiline strings---and enclose a character in single-quotes.
@@ -128,28 +150,32 @@ Those data types and their ranges are:
| Char | 16-bit unsigned Unicode character (0 to 2^16-1, inclusive)
0 to 65,535 |
| String | a sequence of `Char` |
-
-
## `BigInt` and `BigDecimal`
When you need really large numbers, use the `BigInt` and `BigDecimal` types:
+{% tabs type-bigint %}
+{% tab 'Scala 2 and 3' for=type-bigint %}
```scala
val a = BigInt(1_234_567_890_987_654_321L)
val b = BigDecimal(123_456.789)
```
+{% endtab %}
+{% endtabs %}
Where `Double` and `Float` are approximate decimal numbers, `BigDecimal` is used for precise arithmetic, such as when working with currency.
A great thing about `BigInt` and `BigDecimal` is that they support all the operators you’re used to using with numeric types:
+{% tabs type-bigint2 %}
+{% tab 'Scala 2 and 3' for=type-bigint2 %}
```scala
val b = BigInt(1234567890) // scala.math.BigInt = 1234567890
val c = b + b // scala.math.BigInt = 2469135780
val d = b * b // scala.math.BigInt = 1524157875019052100
```
-
-
+{% endtab %}
+{% endtabs %}
## Two notes about strings
@@ -163,28 +189,39 @@ Scala strings are similar to Java strings, but they have two great additional fe
String interpolation provides a very readable way to use variables inside strings.
For instance, given these three variables:
+{% tabs string-inside1 %}
+{% tab 'Scala 2 and 3' for=string-inside1 %}
```scala
val firstName = "John"
val mi = 'C'
val lastName = "Doe"
```
+{% endtab %}
+{% endtabs %}
You can combine those variables in a string like this:
+{% tabs string-inside2 %}
+{% tab 'Scala 2 and 3' for=string-inside2 %}
```scala
println(s"Name: $firstName $mi $lastName") // "Name: John C Doe"
```
+{% endtab %}
+{% endtabs %}
Just precede the string with the letter `s`, and then put a `$` symbol before your variable names inside the string.
To enclose potentially larger expressions inside a string, put them in curly braces:
+{% tabs string-inside3 %}
+{% tab 'Scala 2 and 3' for=string-inside3 %}
```scala
println(s"2 + 2 = ${2 + 2}") // prints "2 + 2 = 4"
val x = -1
println(s"x.abs = ${x.abs}") // prints "x.abs = 1"
```
-
+{% endtab %}
+{% endtabs %}
#### Other interpolators
@@ -193,42 +230,55 @@ If you use an `f` instead of an `s`, you can use `printf`-style formatting synta
Furthermore, a string interpolator is a just special method, and it is possible to define your own.
For instance, some database libraries define the very powerful `sql` interpolator.
-
### Multiline strings
Multiline strings are created by including the string inside three double-quotes:
+{% tabs string-mlines1 %}
+{% tab 'Scala 2 and 3' for=string-mlines1 %}
```scala
val quote = """The essence of Scala:
Fusion of functional and object-oriented
programming in a typed setting."""
```
+{% endtab %}
+{% endtabs %}
One drawback of this basic approach is that the lines after the first line are indented, and look like this:
+{% tabs string-mlines2 %}
+{% tab 'Scala 2 and 3' for=string-mlines2 %}
```scala
"The essence of Scala:
Fusion of functional and object-oriented
programming in a typed setting."
```
+{% endtab %}
+{% endtabs %}
When spacing is important, put a `|` symbol in front of all lines after the first line, and call the `stripMargin` method after the string:
+{% tabs string-mlines3 %}
+{% tab 'Scala 2 and 3' for=string-mlines3 %}
```scala
val quote = """The essence of Scala:
|Fusion of functional and object-oriented
|programming in a typed setting.""".stripMargin
```
+{% endtab %}
+{% endtabs %}
Now all of the lines are left-justified inside the string:
+{% tabs string-mlines4 %}
+{% tab 'Scala 2 and 3' for=string-mlines4 %}
```scala
"The essence of Scala:
Fusion of functional and object-oriented
programming in a typed setting."
```
-
-
+{% endtab %}
+{% endtabs %}
## Type casting
@@ -237,6 +287,8 @@ Value types can be cast in the following way:
For example:
+{% tabs cast1 %}
+{% tab 'Scala 2 and 3' for=cast1 %}
```scala
val b: Byte = 127
val i: Int = b // 127
@@ -244,20 +296,24 @@ val i: Int = b // 127
val face: Char = '☺'
val number: Int = face // 9786
```
+{% endtab %}
+{% endtabs %}
You can only cast to a type if there is no loss of information. Otherwise, you need to be explicit about the cast:
+{% tabs cast2 %}
+{% tab 'Scala 2 and 3' for=cast2 %}
```scala
val x: Long = 987654321
val y: Float = x.toFloat // 9.8765434E8 (note that `.toFloat` is required because the cast results in precision loss)
val z: Long = y // Error
```
+{% endtab %}
+{% endtabs %}
You can also cast a reference type to a subtype.
This will be covered later in the tour.
-
-
## `Nothing` and `null`
`Nothing` is a subtype of all types, also called the **bottom type**.