diff --git a/_overviews/scala3-book/fun-anonymous-functions.md b/_overviews/scala3-book/fun-anonymous-functions.md index c771c1458c..39d87da216 100644 --- a/_overviews/scala3-book/fun-anonymous-functions.md +++ b/_overviews/scala3-book/fun-anonymous-functions.md @@ -116,7 +116,7 @@ In other examples, you can simplify your anonymous functions further. For instance, beginning with the most explicit form, you can print each element in `ints` using this anonymous function with the `List` class `foreach` method: ```scala -ints.foreach((i:Int) => println(i)) +ints.foreach((i: Int) => println(i)) ``` As before, the `Int` declaration isn’t required, and because there’s only one argument, the parentheses around `i` aren’t needed: @@ -131,7 +131,7 @@ Because `i` is used only once in the body of the function, the expression can be ints.foreach(println(_)) ``` -Finally, if an anonymous function consists of one statement that takes a single argument, you don’t need to explicitly name and specify the argument, so the statement can finally be reduced to this: +Finally, if an anonymous function consists of one method call that takes a single argument, you don’t need to explicitly name and specify the argument, so you can finally write only the name of the method (here, `println`): ```scala ints.foreach(println) diff --git a/_overviews/scala3-book/fun-hofs.md b/_overviews/scala3-book/fun-hofs.md index c8d93c46ef..0985c38ea2 100644 --- a/_overviews/scala3-book/fun-hofs.md +++ b/_overviews/scala3-book/fun-hofs.md @@ -37,7 +37,7 @@ As a beneficial side effect of this discussion, once you’re comfortable with t To understand how higher-order functions work, it helps to dig into an example. For instance, you can understand the type of functions `filter` accepts by looking at its Scaladoc. -Here’s the `filter` definition in the `List` class: +Here’s the `filter` definition in the `List[A]` class: ```scala def filter(p: (A) => Boolean): List[A] @@ -102,7 +102,7 @@ Here’s how this works: It’s just like naming a `String` parameter `s` or an `Int` parameter `i`. - The type signature of `f` specifies the *type* of the functions this method will accept. - The `()` portion of `f`’s signature (on the left side of the `=>` symbol) states that `f` takes no input parameters. -- The `Unit` portion of the signature (on the right side of the `=>` symbol) indicates that `f` should return nothing. +- The `Unit` portion of the signature (on the right side of the `=>` symbol) indicates that `f` should not return a meaningful result. - Looking back at the body of the `sayHello` method (on the right side of the `=` symbol), the `f()` statement there invokes the function that’s passed in. Now that we’ve defined `sayHello`, let’s create a function to match `f`’s signature so we can test it. @@ -148,7 +148,7 @@ The only thing to do now is see a few more examples of how to define different t In this method: ```scala -def sayHello(f: () => Unit) +def sayHello(f: () => Unit): Unit ``` We noted that the type signature for `f` is: @@ -157,7 +157,7 @@ We noted that the type signature for `f` is: () => Unit ``` -We know that this means, “a function that takes no input parameters and returns nothing (given by `Unit`).” +We know that this means, “a function that takes no input parameters and returns nothing meaningful (given by `Unit`).” To demonstrate more type signature examples, here’s a function that takes a `String` parameter and returns an `Int`: @@ -255,40 +255,40 @@ executeAndPrint(multiply, 3, 9) // prints 27 ## Function type signature consistency -A great thing about learning about Scala’s function type signatures is that the syntax you use to define function input parameters is the same syntax you use to write anonymous functions and function variables. +A great thing about learning about Scala’s function type signatures is that the syntax you use to define function input parameters is the same syntax you use to write function literals. -For instance, if you were to write an anonymous function that calculates the sum of two integers, you’d write it like this: +For instance, if you were to write a function that calculates the sum of two integers, you’d write it like this: ```scala -(Int, Int) => Int = (a, b) => a + b +val f: (Int, Int) => Int = (a, b) => a + b ``` That code consists of the type signature: ```` -(Int, Int) => Int = (a, b) => a + b ------------------ +val f: (Int, Int) => Int = (a, b) => a + b + ----------------- ```` The input parameters: ```` -(Int, Int) => Int = (a, b) => a + b - ------ +val f: (Int, Int) => Int = (a, b) => a + b + ------ ```` and the body of the function: ```` -(Int, Int) => Int = (a, b) => a + b - ----- +val f: (Int, Int) => Int = (a, b) => a + b + ----- ```` -Scala’s consistency is shown here, where this anonymous function type signature: +Scala’s consistency is shown here, where this function type: ```` -(Int, Int) => Int = (a, b) => a + b ------------------ +val f: (Int, Int) => Int = (a, b) => a + b + ----------------- ```` is the same as the type signature you use to define a function input parameter: diff --git a/_overviews/scala3-book/fun-write-map-function.md b/_overviews/scala3-book/fun-write-map-function.md index 633d9b8fb8..74cab95213 100644 --- a/_overviews/scala3-book/fun-write-map-function.md +++ b/_overviews/scala3-book/fun-write-map-function.md @@ -66,7 +66,7 @@ As a bonus, notice that the `for` expression doesn’t do anything that depends Therefore, you can replace `Int` in the type signature with the generic type parameter `B`: ```scala -def map[A,B](f: (B) => A, xs: List[B]): List[A] = +def map[A, B](f: (B) => A, xs: List[B]): List[A] = for x <- xs yield f(x) ``` @@ -76,7 +76,7 @@ These examples demonstrate that `map` works as desired: ```scala def double(i : Int) = i * 2 -map(double, List(1, 2, 3)) // List(2,4,6) +map(double, List(1, 2, 3)) // List(2, 4, 6) def strlen(s: String) = s.length map(strlen, List("a", "bb", "ccc")) // List(1, 2, 3) diff --git a/_overviews/scala3-book/methods-intro.md b/_overviews/scala3-book/methods-intro.md index a6bf3e2fff..1c1414746c 100644 --- a/_overviews/scala3-book/methods-intro.md +++ b/_overviews/scala3-book/methods-intro.md @@ -9,7 +9,7 @@ next-page: methods-most In Scala 2, _methods_ can be defined inside classes, traits, objects, case classes, and case objects. -But it gets better: In Scala 3 they can also be defined _outside_ any of those constructs with a new feature named Toplevel definitions. +But it gets better: In Scala 3 they can also be defined _outside_ any of those constructs; we say that they are "top-level" definitions, since they are not nested in another definition. In short, methods can now be defined anywhere. Many features of methods are demonstrated in the next section. diff --git a/_overviews/scala3-book/methods-main-methods.md b/_overviews/scala3-book/methods-main-methods.md index 1077e238a2..bee342a45f 100644 --- a/_overviews/scala3-book/methods-main-methods.md +++ b/_overviews/scala3-book/methods-main-methods.md @@ -11,7 +11,7 @@ next-page: methods-summary Scala 3 offers a new way to define programs that can be invoked from the command line: Adding a `@main` annotation to a method turns it into entry point of an executable program: ```scala -@main def hello = println("Hello, world") +@main def hello() = println("Hello, world") ``` Just save that line of code in a file named something like *Hello.scala*---the filename doesn’t have to match the method name---and compile it with `scalac`: @@ -81,7 +81,7 @@ Illegal command line: java.lang.NumberFormatException: For input string: "sixty" The Scala compiler generates a program from an `@main` method `f` as follows: - It creates a class named `f` in the package where the `@main` method was found. -- The class has a static method `main` with the usual signature: It takes an `Array[String]` as argument and returns `Unit`. +- The class has a static method `main` with the usual signature of a Java `main` method: it takes an `Array[String]` as argument and returns `Unit`. - The generated `main` method calls method `f` with arguments converted using methods in the `scala.util.CommandLineParser` object. For instance, the `happyBirthday` method above generates additional code equivalent to the following class: diff --git a/_overviews/scala3-book/methods-most.md b/_overviews/scala3-book/methods-most.md index ac2140a41b..233c51b847 100644 --- a/_overviews/scala3-book/methods-most.md +++ b/_overviews/scala3-book/methods-most.md @@ -7,16 +7,16 @@ previous-page: methods-intro next-page: methods-main-methods --- -This section introduces the various aspects of how to define and call methods in Scala 2. +This section introduces the various aspects of how to define and call methods in Scala 3. ## Defining Methods Scala methods have many features, including these: - Generic (type) parameters -- Automatically provided `using` parameters - Default parameter values - Multiple parameter groups +- Context-provided parameters - By-name parameters - ... @@ -63,7 +63,7 @@ The Scala collections classes have dozens of built-in methods. These examples show how to call them: ```scala -val x = List(1,2,3) +val x = List(1, 2, 3) x.size // 3 x.contains(1) // true @@ -102,7 +102,7 @@ res0: Int = 4 ``` Notice that there’s no need for a `return` statement at the end of the method. -Because almost everything in Scala is an _expression_---meaning that each line of code returns (or _evaluates to) a value---there’s no need to use `return`. +Because almost everything in Scala is an _expression_---meaning that each line of code returns (or _evaluates to_) a value---there’s no need to use `return`. This becomes more clear when you condense that method and write it on one line: @@ -118,6 +118,7 @@ The body of a method can use all the different features of the language: - `for` loops and `for` expressions - Variable assignments - Calls to other methods +- Definitions of other methods As an example of a real-world multiline method, this `getStackTraceAsString` method converts its `Throwable` input parameter into a well-formatted `String`: @@ -202,10 +203,10 @@ When a method takes no parameters, it’s said to have an _arity_ level of _arit Similarly, when a method takes one parameter it’s an _arity-1_ method. When you create arity-0 methods: -- If the method has side effects, such as calling `println`, declare the method with empty parentheses -- If the method does not have side effects---such as getting the size of a collection, which is similar to accessing a field on the collection---leave the parentheses off +- If the method performs side effects, such as calling `println`, declare the method with empty parentheses +- If the method does not perform side effects---such as getting the size of a collection, which is similar to accessing a field on the collection---leave the parentheses off -For example, this method has a side effect, so it’s declared with empty parentheses: +For example, this method performs a side effect, so it’s declared with empty parentheses: ```scala def speak() = println("hi") @@ -218,7 +219,7 @@ speak // error: "method speak must be called with () argument" speak() // prints "hi" ``` -While this is just a convention, following it dramatically improves code readability: It makes it easier to understand at a glance that an arity-0 method has side effects. +While this is just a convention, following it dramatically improves code readability: It makes it easier to understand at a glance that an arity-0 method performs side effects. {% comment %} Some of that wording comes from this page: https://docs.scala-lang.org/style/method-invocation.html @@ -233,7 +234,7 @@ Here’s a method named `isTruthy` that implements the Perl definitions of `true ```scala def isTruthy(a: Any) = - if a == 0 || a == "" then + if a == 0 || a == "" || a == false then false else true @@ -257,7 +258,7 @@ Here’s another version of `isTruthy`, written with a `match` expression : ```scala def isTruthy(a: Matchable) = a match - case 0 | "" => false + case 0 | "" | false => false case _ => true ``` @@ -279,7 +280,7 @@ d.speak() // prints "Woof" ``` Methods can also be marked as `private`. -This makes them private to the current class, and they can’t be overridden in subclasses: +This makes them private to the current class, so they can’t be called nor overridden in subclasses: ```scala class Animal: @@ -290,7 +291,7 @@ class Cat extends Animal: override def breathe() = println("Yo, I’m totally breathing") ``` -If you want to make a method private to the current class and also allow subclasses to override it, mark the method as `protected`, as shown with the `speak` method in this example: +If you want to make a method private to the current class and also allow subclasses to call it or override it, mark the method as `protected`, as shown with the `speak` method in this example: ```scala class Animal: diff --git a/_overviews/scala3-book/packaging-imports.md b/_overviews/scala3-book/packaging-imports.md index b34071123d..ef3b9a16c1 100644 --- a/_overviews/scala3-book/packaging-imports.md +++ b/_overviews/scala3-book/packaging-imports.md @@ -33,26 +33,33 @@ package com.acme.myapp.model class Person ... ``` -By convention, package names should be all lower case, and the formal naming convention is *...*. +By convention, package names should be all lower case, and the formal naming convention is *\.\.\.\*. Although it’s not required, package names typically follow directory structure names, so if you follow this convention, a `Person` class in this project will be found in a *MyApp/src/main/scala/com/acme/myapp/model/Person.scala* file. -### Curly brace packaging style +### Using multiple packages in the same file -The other way to declare packages in Scala is by using the curly brace namespace notation used in languages like C, C++, and C#: +The syntax shown above applies to the entire source file: all the definitions in the file +`Person.scala` belong to package `com.acme.myapp.model`, according to the package clause +at the beginning of the file. + +Alternatively, it is possible to write package clauses that apply only to the definitions +they contain: ```scala -package users { - package administrators { - class AdminUser - } - package normalusers { - class NormalUser - } -} +package users: + + package administrators: // the full name of this package is users.administrators + class AdminUser // the full name of this class is users.administrators.AdminUser + + package normalusers: // the full name of this package is users.normalusers + class NormalUser // the full name of this class is users.normalusers.NormalUser ``` +Note that the package names are followed by a colon, and that the defininitions within +a package are indented. + The advantages of this approach are that it allows for package nesting, and provides more obvious control of scope and encapsulation, especially within the same file. @@ -92,27 +99,27 @@ A note before moving on: In Scala you can import one member from a package like this: ```scala -import java.io.File +import scala.concurrent.Future ``` and multiple members like this: ```scala -import java.io.File -import java.io.IOException -import java.io.FileNotFoundException +import scala.concurrent.Future +import scala.concurrent.Promise +import scala.concurrent.blocking ``` When importing multiple members, you can import them more concisely like this: ```scala -import java.io.{File, IOException, FileNotFoundException} +import scala.concurrent.{Future, Promise, blocking} ``` -When you want to import everything from the *java.io* package, use this syntax: +When you want to import everything from the *scala.concurrent* package, use this syntax: ```scala -import java.io.* +import scala.concurrent.* ``` @@ -170,13 +177,13 @@ val res0: java.util.ArrayList[String] = [] Because those Java classes are hidden, you can also use the Scala `List`, `Set`, and `Map` classes without having a naming collision: ```scala -scala> val a = List(1,2,3) +scala> val a = List(1, 2, 3) val a: List[Int] = List(1, 2, 3) -scala> val b = Set(1,2,3) +scala> val b = Set(1, 2, 3) val b: Set[Int] = Set(1, 2, 3) -scala> val c = Map(1->1, 2->2) +scala> val c = Map(1 -> 1, 2 -> 2) val c: Map[Int, Int] = Map(1 -> 1, 2 -> 2) ``` @@ -241,7 +248,7 @@ Two packages are implicitly imported into the scope of all of your source code f - java.lang.* - scala.* -The Scala `Predef` object is also imported by default. +The members of the Scala object `Predef` are also imported by default. > If you ever wondered why you can use classes like `List`, `Vector`, `Map`, etc., without importing them, they’re available because of definitions in the `Predef` object.