8000 Some suggestions in the Scala 3 book (2) by julienrf · Pull Request #2073 · scala/docs.scala-lang · GitHub
[go: up one dir, main page]

Skip to content

Some suggestions in the Scala 3 book (2) #2073

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
Jun 14, 2021
Merged
Show file tree
Hide file tree
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
34 changes: 11 additions & 23 deletions _overviews/scala3-book/control-structures.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,26 +144,14 @@ scala> for i <- ints do println(i)
3
````

When you need a multiline block of code following the `for` generator, use either of these approaches:
When you need a multiline block of code following the `for` generator, use the following syntax:

```scala
// option 1
for
i <- ints
do
val x = i * 2
println(s"i = $i, x = $x")

// option 2
for (i <- ints)
val x = i * 2
println(s"i = $i, x = $x")

// option 3
for (i <- ints) {
val x = i * 2
println(s"i = $i, x = $x")
}
```

### Multiple generators
Expand Down Expand Up @@ -276,7 +264,7 @@ val list =
yield
i * 2

// result: list == Vector(20, 22, 24)
// list: IndexedSeq[Int] = Vector(20, 22, 24)
```

After that `for` expression runs, the variable `list` is a `Vector` that contains the values shown.
Expand All @@ -288,7 +276,7 @@ This is how the expression works:
It multiples it by `2`, then yields the value `22`.
You can think of these yielded values as accumulating in a temporary holding place.
3. Finally the loop gets the number `12` from the range, multiplies it by `2`, yielding the number `24`.
The loop completes at this point and yields the final result, the `Vector(20,22,24)`.
The loop completes at this point and yields the final result, the `Vector(20, 22, 24)`.

{% comment %}
NOTE: This is a place where it would be great to have a TIP or NOTE block:
Expand All @@ -297,7 +285,7 @@ NOTE: This is a place where it would be great to have a TIP or NOTE block:
While the intent of this section is to demonstrate `for` expressions, it can help to know that the `for` expression shown is equivalent to this `map` method call:

```scala
val list = (10 to 12).map { i => i * 2}
val list = (10 to 12).map(i => i * 2)
```

`for` expressions can be used any time you need to traverse all of the elements in a collection and apply an algorithm to those elements to create a new list.
Expand All @@ -312,7 +300,7 @@ val capNames = for name <- names yield
val capName = nameWithoutUnderscore.capitalize
capName

// result: List[String] = List(Olivia, Walter, Peter)
// capNames: List[String] = List(Olivia, Walter, Peter)
```


Expand All @@ -329,7 +317,7 @@ def between3and10(xs: List[Int]): List[Int] =
if x <= 10
yield x

between3and10(List(1, 3, 7, 11)) // result: List(3, 7)
between3and10(List(1, 3, 7, 11)) // : List[Int] = List(3, 7)
```


Expand Down Expand Up @@ -386,7 +374,7 @@ If it’s between `0` and `6`, `day` is bound to a string that represents one of
Otherwise, the catch-all case is represented by the `_` character, and `day` is bound to the string, `"invalid day"`.

> When writing simple `match` expressions like this, it’s recommended to use the `@switch` annotation on the variable `i`.
> This annotation provides a compile time warning if the switch can’t be compiled to a `tableswitch` or `lookupswitch`, which are better for performance.
> This annotation provides a compile-time warning if the switch can’t be compiled to a `tableswitch` or `lookupswitch`, which are better for performance.


### Using the default value
Expand Down Expand Up @@ -417,7 +405,7 @@ val evenOrOdd = i match
```


### Using `if` expressions in `case` statements
### Using `if` guards in `case` clauses

You can also use guards in the `case`s of a match expression.
In this example the second and third `case` both use guards to match multiple integer values:
Expand Down Expand Up @@ -528,8 +516,8 @@ def pattern(x: Matchable): String = x match
case a: Array[Int] => s"array of int: ${a.mkString(",")}"
case as: Array[String] => s"string array: ${as.mkString(",")}"
case d: Dog => s"dog: ${d.name}"
case list: List[_] => s"got a List: $list"
case m: Map[_, _] => m.toString
case list: List[?] => s"got a List: $list"
case m: Map[?, ?] => m.toString

// the default wildcard pattern
case _ => "Unknown"
Expand Down Expand Up @@ -561,7 +549,7 @@ finally
println("Came to the 'finally' clause.")
```

Assuming that the `openAndReadAFile` method uses the Java `java.io._` classes to read a file and doesn’t catch its exceptions, attempting to open and read a file can result in both a `FileNotFoundException` and an `IOException`, and those two exceptions are caught in the `catch` block of this example.
Assuming that the `openAndReadAFile` method uses the Java `java.io.*` classes to read a file and doesn’t catch its exceptions, attempting to open and read a file can result in both a `FileNotFoundException` and an `IOException`, and those two exceptions are caught in the `catch` block of this example.


[matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
2 changes: 1 addition & 1 deletion _overviews/scala3-book/domain-modeling-fp.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ An FP design is implemented in a similar way:

> As we will see, reasoning about programs in this style is quite different from the object-oriented programming.
> Data in FP simply **is**:
> Separating functionality from your data let's you inspect your data without having to worry about behavior.
> Separating functionality from your data lets you inspect your data without having to worry about behavior.

In this chapter we’ll model the data and operations for a “pizza” in a pizza store.
You’ll see how to implement the “data” portion of the Scala/FP model, and then you’ll see several different ways you can organize the operations on that data.
Expand Down
21 changes: 10 additions & 11 deletions _overviews/scala3-book/domain-modeling-oop.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,11 @@ When designing software in Scala, it’s often helpful to only consider using cl
NOTE: I think “leaves” may technically be the correct word to use, but I prefer “leafs.”
{% endcomment %}

```text
traits T1 T2 ... T3
composed traits S extends T1, T2 ... S extends T2, T3
classes C extends S, T3
instances new C
```
| Traits | `T1`, `T2`, `T3`
| Composed traits | `S extends T1, T2`, `S extends T2, T3`
| Classes | `C extends S, T3`
| Instances | `C()`

This is even more the case in Scala 3, where traits now can also take parameters, further eliminating the need for classes.

#### Defining Classes
Expand Down Expand Up @@ -147,7 +146,7 @@ class Counter:
// can only be observed by the method `count`
private var currentCount = 0

def tick() = currentCount += 1
def tick(): Unit = currentCount += 1
def count: Int = currentCount
```
Every instance of the class `Counter` has its own private state that can only be observed through the method `count`, as the following interaction illustrates:
Expand Down Expand Up @@ -198,7 +197,7 @@ There are a few things that need explanation.
#### Abstract Type Members
The declaration `type S <: Subject` says that within the trait `SubjectObserver` we can refer to some _unknown_ (that is, abstract) type that we call `S`.
However, the type is not completely unknown: we know at least that it is _some subtype_ of the trait `Subject`.
All traits and classes extending `SubjectObserer` are free to chose any type for `S` as long as the chosen type is a subtype of `Subject`.
All traits and classes extending `SubjectObserer` are free to choose any type for `S` as long as the chosen type is a subtype of `Subject`.
The `<: Subject` part of the declaration is also referred to as an _upper bound on `S`_.

#### Nested Traits
Expand All @@ -210,12 +209,12 @@ The second trait, `Subject`, defines one private field `observers` to store all
Subscribing to a subject simply stores the object into this list.
Again, the type of parameter `obs` is `O`, not `Observer`.

#### Selftype Annotations
#### Self-type Annotations
Finally, you might have wondered what the `self: S =>` on trait `Subject` is supposed to mean.
This is called a _selftype annotation_.
This is called a _self-type annotation_.
It requires subtypes of `Subject` to also be subtypes of `S`.
This is necessary to be able to call `obs.notify` with `this` as an argument, since it requires a value of type `S`.
If `S` was a _concrete_ type, the selftype annotation could be replaced by `trait Subject extends S`.
If `S` was a _concrete_ type, the self-type annotation could be replaced by `trait Subject extends S`.

### Implementing the Component
We can now implement the above component and define the abstract type members to be concrete types:
Expand Down
20 changes: 1 addition & 19 deletions _overviews/scala3-book/domain-modeling-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,9 @@ class Movie(var name: String, var director: String, var year: Int)
```

These examples show that Scala has a very lightweight way to declare classes.
The definition of the class `Person` roughly corresponds to the following, more explicit, version:

```scala
class Person:
// fields
var name: String = null
var vocation: String = null

// constructor
def this(_name: String, _vocation: String) =
// call to the super constructor
this()
// assigning the fields
name = _name
vocation = _vocation
```

This version defines the two fields `name` and `vocation`, together with a constructor that accepts values for those two fields and assigns them.

All of the parameters of our example classes are defined as `var` fields, which means they are mutable: you can read them, and also modify them.
If you want them to be immutable---read only---create them as `val` fields instead.
If you want them to be immutable---read only---create them as `val` fields instead, or use a case class.

Prior to Scala 3, you used the `new` keyword to create a new instance of a class:

Expand Down
7 changes: 4 additions & 3 deletions _overviews/scala3-book/first-look-at-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,14 @@ A common use is to signal non-termination, such as a thrown exception, program e

`Null` is a subtype of all reference types (i.e. any subtype of `AnyRef`).
It has a single value identified by the keyword literal `null`.
`Null` is provided mostly for interoperability with other JVM languages and should almost never be used in Scala code.
Alternatives to `null` are discussed in the [Functional Programming chapter][fp] of this book, and the [API documentation][option-api].

Currently, the usage of `null` is considered bad practice. It should be used mostly for interoperability with other JVM languages. An opt-in compiler option changes the status of `Null` to fix the caveats related to its usage. This option might become the default in a future version of Scala. You can learn more about it [here][safe-null].

In the meantime, `null` should almost never be used in Scala code.
Alternatives to `null` are discussed in the [Functional Programming chapter][fp] of this book, and the [API documentation][option-api].

[reference]: {{ site.scala3ref }}/overview.html
[matchable]: {{ site.scala3ref }}/other-new-features/matchable.html
[interpolation]: {% link _overviews/core/string-interpolation.md %}
[fp]: {% link _overviews/scala3-book/fp-intro.md %}
[option-api]: https://dotty.epfl.ch/api/scala/Option.html
[safe-null]: {{ site.scala3ref }}/other-new-features/explicit-nulls.html
0