-
Notifications
You must be signed in to change notification settings - Fork 1k
Some suggestions in the Scala 3 book #2062
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
julienrf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- 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: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer “computing a result” over “achieving an effect”, which sounded more imperative to me. |
||
|
||
```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 | ||
julienrf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have merged “types make your code easier to maintain” and “Scalability” into just “Scalability and maintainability”. |
||
- 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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have removed “method arguments for implicit parameters”, I think it’s too early to introduce this jargon. |
||
|
||
{% 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) | ||
* [ 8000 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: | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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: | ||
Comment on lines
-234
to
+239
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it’s preferable to mention one reference syntax and to say that the alternative syntax is supported for compatibility reasons, primarily, otherwise I’m afraid readers will feel lost if we show them several ways of doing one thing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
```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 | ||
``` | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 179B // : Person = Person(Reginald Kenneth Dwight,Singer) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’m not entirely sure what was the intent by writing “Person = Person(...)”. If the goal is to look like the output of a worksheet in Metals, then we should add the colons just before the inferred type. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you can just show the I’m not sure why I included the |
||
|
||
// 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. | ||
|
||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that “fusion of FP and OOP in a typed setting” was a bit redundant with the previous mentions of FP and OOP, so I’ve changed the last point to highlight only the static type system.