diff --git a/_overviews/scala3-book/introduction.md b/_overviews/scala3-book/introduction.md index c2e131e26c..3d3558203d 100644 --- a/_overviews/scala3-book/introduction.md +++ b/_overviews/scala3-book/introduction.md @@ -12,8 +12,8 @@ The goal of this book is to provide an informal introduction to the Scala langua It touches on all Scala topics, in a relatively light manner. If at any time while you’re reading this book and want more information on a specific feature, you’ll find links to our [_Reference_ documentation][reference], which covers many new features of the Scala language in more detail. -Over the course of this book, we hope to demonstrate that Scala is a beautiful, expressive programming language, with a clean, modern syntax, and supports functional programming (FP), object-oriented programming (OOP), and a fusion of FP and OOP in a typed setting. -Scala’s syntax, grammar, and features have been re-thought, debated in an open process, and updated in 2020 to be more clear and easier to understand than ever before. +Over the course of this book, we hope to demonstrate that Scala is a beautiful, expressive programming language, with a clean, modern syntax, which supports functional programming (FP) and object-oriented programming (OOP), and that provides a safe static type system. +Scala’s syntax, grammar, and features have been re-thought, debated in an open process, and updated in 2020 to be clearer and easier to understand than ever before. The book begins with a whirlwind tour of many of Scala’s features in the [“A Taste of Scala” section][taste]. After that tour, the sections that follow it provide more details on those language features. diff --git a/_overviews/scala3-book/scala-features.md b/_overviews/scala3-book/scala-features.md index 048d7e4519..f0c8efb129 100644 --- a/_overviews/scala3-book/scala-features.md +++ b/_overviews/scala3-book/scala-features.md @@ -30,8 +30,8 @@ Looking at Scala from the proverbial “30,000 foot view,” you can make the fo - It has a concise, readable syntax - It’s statically-typed (but feels dynamic) - It has an expressive type system -- It’s a pure functional programming (FP) language -- It’s a pure object-oriented programming (OOP) language +- It’s a functional programming (FP) language +- It’s an object-oriented programming (OOP) language - It supports the fusion of FP and OOP - Contextual abstractions provide a clear way to implement _term inference_ - It runs on the JVM (and in the browser) @@ -63,7 +63,7 @@ val newNumbers = double(oldNumbers) ``` That code instructs the compiler what to do on a step-by-step basis. -Instead, we write high-level, functional code using higher-order functions and lambdas like this to achieve the same effect: +Instead, we write high-level, functional code using higher-order functions and lambdas like this to compute the same result: ```scala val newNumbers = oldNumbers.map(_ * 2) @@ -92,7 +92,7 @@ nums.filter(i => i > 1) nums.filter(_ > 1) ``` -And traits, classes, and methods are defined with a clean, light syntax: +Traits, classes, and methods are defined with a clean, light syntax: ```scala trait Animal: @@ -128,15 +128,13 @@ As Heather Miller states, Scala is considered to be a [strong, statically-typed - Correctness: you catch most errors at compile-time - Great IDE support - - Code completion + - Reliable code completion - Catching errors at compile-time means catching mistakes as you type - Easy and reliable refactoring - - Reliable code completion - You can refactor your code with confidence - Method type declarations tell readers what the method does, and help serve as documentation -- Types make your code easier to maintain -- Scalability: types help ensure correctness across arbitrarily large applications and development teams -- Strong typing in combination with excellent inference enables mechanisms like [contextual abstraction]({{ site.scala3ref }}/contextual/motivation.html) that allows you to omit boilerplate code. Often, this boilerplate code can be inferred by the compiler, based on type definitions and a given context (e.g. method arguments for implicit parameters). +- Scalability and maintainability: types help ensure correctness across arbitrarily large applications and development teams +- Strong typing in combination with excellent inference enables mechanisms like [contextual abstraction]({{ site.scala3ref }}/contextual/motivation.html) that allows you to omit boilerplate code. Often, this boilerplate code can be inferred by the compiler, based on type definitions and a given context. {% comment %} In that list: @@ -156,11 +154,11 @@ In that list: - i removed these items until we can replace them: * [Compound types](/tour/compound-types.html) -* [Implicit parameters](/tour/implicit-parameters.html) and [conversions](/tour/implicit-conversions.html) +* [conversions](/tour/implicit-conversions.html) * [Explicitly typed self references](/tour/self-types.html) {% endcomment %} -Scala’s expressive type system enforces, at compile-time, that abstractions are used in a safe and coherent manner. +Scala’s type system enforces, at compile-time, that abstractions are used in a safe and coherent manner. In particular, the type system supports: - [Type inference](/tour/type-inference.html) @@ -187,11 +185,11 @@ In particular, the type system supports: In combination, these features provide a powerful basis for the safe reuse of programming abstractions and for the type-safe extension of software. -### A pure FP language +### A functional programming language Scala is a functional programming (FP) language, meaning: -- Functions are variables, and can be passed around like any other variable +- Functions are values, and can be passed around like any other value - Higher-order functions are directly supported - Lambdas are built in - Everything in Scala is an expression that returns a value @@ -200,10 +198,10 @@ Scala is a functional programming (FP) language, meaning: - Those collection classes come with dozens of functional methods: they don’t mutate the collection, but instead return an updated copy of the data -### A pure OOP language +### An object-oriented language -Scala is a _pure_ object-oriented programming (OOP) language. -Every variable is an object and every “operator” is a method. +Scala is an object-oriented programming (OOP) language. +Every value is an instance of a class and every “operator” is a method. In Scala, all types inherit from a top-level class `Any`, whose immediate children are `AnyVal` (_value types_, such as `Int` and `Boolean`) and `AnyRef` (_reference types_, as in Java). This means that the Java distinction between primitive types and boxed types (e.g. `int` vs. `Integer`) isn’t present in Scala. @@ -236,9 +234,9 @@ Following Haskell, Scala was the second popular language to have some form of _i In Scala 3 these concepts have been completely re-thought and more clearly implemented. The core idea is _term inference_: Given a type, the compiler synthesizes a “canonical” term that has that type. -In Scala, an implicit parameter directly leads to an inferred argument term that could also be written down explicitly. +In Scala, a context parameter directly leads to an inferred argument term that could also be written down explicitly. -Use cases for this concept include implementing type classes, establishing context, dependency injection, expressing capabilities, computing new types, and proving relationships between them. +Use cases for this concept include implementing [type classes]({% link _overviews/scala3-book/ca-type-classes.md %}), establishing context, dependency injection, expressing capabilities, computing new types, and proving relationships between them. Scala 3 makes this process more clear than ever before. Read about contextual abstractions in the [Reference documentation]({{ site.scala3ref }}/contextual/motivation.html). @@ -442,7 +440,7 @@ Serialization: - [ScalaPB](https://github.com/scalapb/ScalaPB) -Science and data analysis: +### Science and data analysis: - [Algebird](https://github.com/twitter/algebird) - [Spire](https://github.com/typelevel/spire) @@ -461,7 +459,7 @@ Science and data analysis: - [TensorFlow Scala](https://github.com/eaplatanios/tensorflow_scala) -### FP & FRP +### Functional Programming & Functional Reactive Programming FP: diff --git a/_overviews/scala3-book/taste-collections.md b/_overviews/scala3-book/taste-collections.md index e40b85887b..67fdbc1d61 100644 --- a/_overviews/scala3-book/taste-collections.md +++ b/_overviews/scala3-book/taste-collections.md @@ -60,15 +60,13 @@ nums.map(_.toUpperCase) // List("ONE", "TWO") nums.flatMap(_.toUpperCase) // List('O', 'N', 'E', 'T', 'W', 'O') ``` -These examples show how the “fold” and “reduce” methods are used to sum the values in a sequence of integers: +These examples show how the “foldLeft” and “reduceLeft” methods are used to sum the values in a sequence of integers: ```scala val firstTen = (1 to 10).toList // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) -firstTen.reduce(_ + _) // 55 firstTen.reduceLeft(_ + _) // 55 -firstTen.fold(100)(_ + _) // 155 (100 is a “seed” value) -firstTen.foldLeft(100)(_ + _) // 155 +firstTen.foldLeft(100)(_ + _) // 155 (100 is a “seed” value) ``` There are many more methods available to Scala collections classes, and they’re demonstrated in the [Collections chapter][collections], and in the [API Documentation][api]. @@ -93,9 +91,9 @@ val t = (11, "eleven", Person("Eleven")) Once you have a tuple, you can access its values by binding them to variables, or access them by number: ```scala -t._1 // 11 -t._2 // "eleven" -t._3 // Person("Eleven") +t(0) // 11 +t(1) // "eleven" +t(2) // Person("Eleven") ``` You can also use this _extractor_ approach to assign the tuple fields to variable names: diff --git a/_overviews/scala3-book/taste-control-structures.md b/_overviews/scala3-book/taste-control-structures.md index a527f603d2..5c30f73da4 100644 --- a/_overviews/scala3-book/taste-control-structures.md +++ b/_overviews/scala3-book/taste-control-structures.md @@ -186,7 +186,7 @@ This example shows (a) how to use a `match` expression as the body of a method, ```scala // getClassAsString is a method that takes a single argument of any type. -def getClassAsString(x: Any): String = x match +def getClassAsString(x: Matchable): String = x match case s: String => s"'$s' is a String" case i: Int => "Int" case d: Double => "Double" @@ -199,6 +199,10 @@ getClassAsString("hello") // 'hello' is a String getClassAsString(List(1, 2, 3)) // List ``` +The method `getClassAsString` takes as a parameter a value of type [Matchable]({{ site.scala3ref }}/other-new-features/matchable.html), which can be +any type supporting pattern matching (some types don’t support pattern matching because this could +break encapsulation). + There’s _much_ more to pattern matching in Scala. Patterns can be nested, results of patterns can be bound, and pattern matching can even be user-defined. See the pattern matching examples in the [Control Structures chapter][control] for more details. @@ -231,29 +235,26 @@ It’s one-line syntax looks like this: while x >= 0 do x = f(x) ``` -Again, Scala’s control structure syntax is flexible, and you can write this code in different ways depending on your preferences: +In Scala 2, the syntax was a bit different. The condition was surrounded by parentheses, and +there was no `do` keyword: ```scala while (x >= 0) do x = f(x) while (x >= 0) { x = f(x) } ``` +Scala 3 still supports the Scala 2 syntax for the sake of compatibility. + The `while` loop multiline syntax looks like this: ```scala var x = 1 -// without parentheses while x < 3 do println(x) x += 1 - -// with parentheses -while (x < 3) - println(x) - x += 1 ``` diff --git a/_overviews/scala3-book/taste-functions.md b/_overviews/scala3-book/taste-functions.md index 7977f6d600..b103dba666 100644 --- a/_overviews/scala3-book/taste-functions.md +++ b/_overviews/scala3-book/taste-functions.md @@ -11,13 +11,13 @@ next-page: taste-objects Scala has most features you’d expect in a functional programming language, including: -- Lambdas +- Lambdas (anonymous functions) - Higher-order functions (HOFs) - Immutable collections in the standard library Lambdas, also known as _anonymous functions_, are a big part of keeping your code concise but readable. -The `map` method of the `List` class is a typical example of a higher-order function---a function that takes a lambda as parameter. +The `map` method of the `List` class is a typical example of a higher-order function---a function that takes a function as parameter. These two examples are equivalent, and show how to multiply each number in a list by `2` by passing a lambda into the `map` method: diff --git a/_overviews/scala3-book/taste-methods.md b/_overviews/scala3-book/taste-methods.md index 011ba23bd7..2718059bb1 100644 --- a/_overviews/scala3-book/taste-methods.md +++ b/_overviews/scala3-book/taste-methods.md @@ -128,7 +128,7 @@ extension (s: String) ## See also Scala Methods can be much more powerful: they can take type parameters and context parameters. -They are covered in detail in the [Data Modeling][data-1] section. +They are covered in detail in the [Domain Modeling][data-1] section. diff --git a/_overviews/scala3-book/taste-modeling.md b/_overviews/scala3-book/taste-modeling.md index aaee4fa19a..20c605c6f9 100644 --- a/_overviews/scala3-book/taste-modeling.md +++ b/_overviews/scala3-book/taste-modeling.md @@ -81,7 +81,7 @@ c.stopRunning() // "No need to stop" ``` If that code makes sense---great, you’re comfortable with traits as interfaces. -If not, don’t worry, they’re explained in more detail in the [Data Modeling][data-1] chapter. +If not, don’t worry, they’re explained in more detail in the [Domain Modeling][data-1] chapter. ### Classes @@ -106,7 +106,7 @@ Notice that the class declaration creates a constructor: val p = Person("John", "Stephens") ``` -Constructors and other class-related topics are covered in the [Data Modeling][data-1] chapter. +Constructors and other class-related topics are covered in the [Domain Modeling][data-1] chapter. ## FP Domain Modeling @@ -170,7 +170,7 @@ enum Nat: case Succ(pred: Nat) ``` -Enums are covered in detail in the [Data Modeling][data-1] section of this book, and in the [Reference documentation]({{ site.scala3ref }}/enums/enums.html). +Enums are covered in detail in the [Domain Modeling][data-1] section of this book, and in the [Reference documentation]({{ site.scala3ref }}/enums/enums.html). ### Case classes @@ -183,7 +183,7 @@ When the compiler sees the `case` keyword in front of a `class` it has these eff - An `unapply` method is generated, which lets you use case classes in more ways in `match` expressions. - A `copy` method is generated in the class. This provides a way to create updated copies of the object without changing the original object. -- `equals` and `hashCode` methods are generated. +- `equals` and `hashCode` methods are generated to implement structural equality. - A default `toString` method is generated, which is helpful for debugging. @@ -206,7 +206,7 @@ case class Person( val p = Person("Reginald Kenneth Dwight", "Singer") // a good default toString method -p // Person = Person(Reginald Kenneth Dwight,Singer) +p // : Person = Person(Reginald Kenneth Dwight,Singer) // can access its fields, which are immutable p.name // "Reginald Kenneth Dwight" @@ -215,10 +215,10 @@ p.name = "Joe" // error: can’t reassign a val field // when you need to make a change, use the `copy` method // to “update as you copy” val p2 = p.copy(name = "Elton John") -p2 // Person = Person(Elton John,Singer) +p2 // : Person = Person(Elton John,Singer) ``` -See the [Data Modeling][data-1] sections for many more details on `case` classes. +See the [Domain Modeling][data-1] sections for many more details on `case` classes. diff --git a/_overviews/scala3-book/taste-objects.md b/_overviews/scala3-book/taste-objects.md index 1ba49e30d6..ae522627f1 100644 --- a/_overviews/scala3-book/taste-objects.md +++ b/_overviews/scala3-book/taste-objects.md @@ -1,7 +1,7 @@ --- -title: Objects +title: Singleton Objects type: section -description: This section provides an introduction to the use of objects in Scala 3. +description: This section provides an introduction to the use of singleton objects in Scala 3. num: 12 previous-page: taste-functions next-page: taste-collections diff --git a/_overviews/scala3-book/why-scala-3.md b/_overviews/scala3-book/why-scala-3.md index e5f317f9f3..e6c5b2bd96 100644 --- a/_overviews/scala3-book/why-scala-3.md +++ b/_overviews/scala3-book/why-scala-3.md @@ -45,7 +45,7 @@ For instance, a `List` is defined as a class---technically it’s an abstract cl val x = List(1, 2, 3) ``` -However, what appears to the programmer to be a simple `List` is actually built from a combination of several specialized types, including an abstract class named `AbstractSeq`, traits like `LinearSeq` and `LinearSeqOps`, and more. +However, what appears to the programmer to be a simple `List` is actually built from a combination of several specialized types, including abstract classes named `Iterable`, `Seq`, and `LinearSeq`. Those types are similarly composed of other small, modular units of code. In addition to building a type like `List` from a series of modular traits, the `List` API also consists of dozens of other methods, many of which are higher-order functions: @@ -67,7 +67,7 @@ The `List` class is immutable, so all of those methods return new values, as sho ## 2) A dynamic feel Scala’s _type inference_ often makes the language feel dynamically typed, even though it’s statically typed. -This is true with variable assignment: +This is true with variable declaration: ```scala val a = 1 @@ -108,7 +108,7 @@ val b: Password | Username = if (true) name else password ## 3) Concise syntax -Scala is a low ceremony, “concise but still readable” language. For instance, variable type assignment is concise: +Scala is a low ceremony, “concise but still readable” language. For instance, variable declaration is concise: ```scala val a = 1 @@ -120,8 +120,8 @@ Creating types like traits, classes, and enumerations are concise: ```scala trait Tail: - def wagTail: Unit - def stopTail: Unit + def wagTail(): Unit + def stopTail(): Unit enum Topping: case Cheese, Pepperoni, Sausage, Mushrooms, Onions @@ -151,7 +151,7 @@ All of these expressions and many more are concise, and still very readable: wha Implicits in Scala 2 were a major distinguishing design feature. They represented _the_ fundamental way to abstract over context, with a unified paradigm that served a great variety of use cases, among them: -- Implementing type classes +- Implementing [type classes]({% link _overviews/scala3-book/ca-type-classes.md %}) - Establishing context - Dependency injection - Expressing capabilities @@ -208,7 +208,7 @@ See that chapter for more details on these features. Scala can be used on the server side with terrific frameworks: - The [Play Framework](https://www.playframework.com) lets you build highly scalable server-side applications and microservices -- [Akka Actors](https://akka.io) let you use the actor model to greatly simplify parallel and concurrent software applications +- [Akka Actors](https://akka.io) let you use the actor model to greatly simplify distributed and concurrent software applications Scala can also be used in the browser with the [Scala.js project](https://www.scala-js.org), which is a type-safe replacement for JavaScript. The Scala.js ecosystem [has dozens of libraries](https://www.scala-js.org/libraries) to let you use React, Angular, jQuery, and many other JavaScript and Scala libraries in the browser. @@ -227,50 +227,50 @@ While these all use the `List` class, the same methods work with other collectio Here are some examples: ```scala -List.range(1, 3) // List(1, 2) -List.range(1, 6, 2) // List(1, 3, 5) -List.fill(3)("foo") // List(foo, foo, foo) -List.tabulate(3)(n => n * n) // List(0, 1, 4) -List.tabulate(4)(n => n * n) // List(0, 1, 4, 9) - -val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10) -a.distinct // List(10, 20, 30, 40) -a.drop(2) // List(30, 40, 10) -a.dropRight(2) // List(10, 20, 30) -a.dropWhile(_ < 25) // List(30, 40, 10) -a.filter(_ < 25) // List(10, 20, 10) -a.filter(_ > 100) // List() -a.find(_ > 20) // Some(30) -a.head // 10 -a.headOption // Some(10) -a.init // List(10, 20, 30, 40) -a.intersect(List(19,20,21)) // List(20) -a.last // 10 -a.lastOption // Some(10) -a.map(_ * 2) // List(20, 40, 60, 80, 20) -a.slice(2,4) // List(30, 40) -a.tail // List(20, 30, 40, 10) -a.take(3) // List(10, 20, 30) -a.takeRight(2) // List(40, 10) -a.takeWhile(_ < 30) // List(10, 20) -a.filter(_ < 30).map(_ * 10) // List(100, 200) +List.range(1, 3) // List(1, 2) +List.range(start = 1, end = 6, step = 2) // List(1, 3, 5) +List.fill(3)("foo") // List(foo, foo, foo) +List.tabulate(3)(n => n * n) // List(0, 1, 4) +List.tabulate(4)(n => n * n) // List(0, 1, 4, 9) + +val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10) +a.distinct // List(10, 20, 30, 40) +a.drop(2) // List(30, 40, 10) +a.dropRight(2) // List(10, 20, 30) +a.dropWhile(_ < 25) // List(30, 40, 10) +a.filter(_ < 25) // List(10, 20, 10) +a.filter(_ > 100) // List() +a.find(_ > 20) // Some(30) +a.head // 10 +a.headOption // Some(10) +a.init // List(10, 20, 30, 40) +a.intersect(List(19,20,21)) // List(20) +a.last // 10 +a.lastOption // Some(10) +a.map(_ * 2) // List(20, 40, 60, 80, 20) +a.slice(2, 4) // List(30, 40) +a.tail // List(20, 30, 40, 10) +a.take(3) // List(10, 20, 30) +a.takeRight(2) // List(40, 10) +a.takeWhile(_ < 30) // List(10, 20) +a.filter(_ < 30).map(_ * 10) // List(100, 200) val fruits = List("apple", "pear") -fruits.map(_.toUpperCase) // List(APPLE, PEAR) -fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R) +fruits.map(_.toUpperCase) // List(APPLE, PEAR) +fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R) val nums = List(10, 5, 8, 1, 7) -nums.sorted // List(1, 5, 7, 8, 10) -nums.sortWith(_ < _) // List(1, 5, 7, 8, 10) -nums.sortWith(_ > _) // List(10, 8, 7, 5, 1) +nums.sorted // List(1, 5, 7, 8, 10) +nums.sortWith(_ < _) // List(1, 5, 7, 8, 10) +nums.sortWith(_ > _) // List(10, 8, 7, 5, 1) ``` -## 8) Built-in practices +## 8) Built-in best practices Scala idioms encourage best practices in many ways. -For immutability, you’re encouraged to create immutable `val` fields: +For immutability, you’re encouraged to create immutable `val` declarations: ```scala val a = 1 // immutable variable @@ -283,7 +283,7 @@ val b = List(1,2,3) // List is immutable val c = Map(1 -> "one") // Map is immutable ``` -Case classes are primarily intended for use in functional programming, and their parameters are immutable: +Case classes are primarily intended for use in [domain modeling]({% link _overviews/scala3-book/domain-modeling-intro.md %}), and their parameters are immutable: ```scala case class Person(name: String) @@ -386,6 +386,7 @@ _Safety_ is related to several new and changed features: - Multiversal equality - Restricting implicit conversions - Null safety +- Safe initialization Good examples of _ergonomics_ are enumerations and extension methods, which have been added to Scala 3 in a very readable manner: diff --git a/scala3/contribute-to-docs.md b/scala3/contribute-to-docs.md index 91b467766f..642a12f2c0 100644 --- a/scala3/contribute-to-docs.md +++ b/scala3/contribute-to-docs.md @@ -16,7 +16,7 @@ We welcome contributions from the community to every aspect of the documentation ### How can I contribute? -In general, there is many different ways you could help us: +In general, there are many ways you can help us: - **Confused about something in any of the docs?** Open an issue. - **Found something not up-to-date?** Open an issue or create a PR.