Skip to content

Use Em Dash Syntax in Scala 3 doc #1864

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 2 commits into from
Dec 23, 2020
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
2 changes: 1 addition & 1 deletion _overviews/scala3-book/ca-given-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ object B:

## Discussion

The wildcard selector `_` brings all definitions other than givens or extensions into scope, whereas a `given` selector brings all *givens*including those resulting from extensionsinto scope.
The wildcard selector `_` brings all definitions other than givens or extensions into scope, whereas a `given` selector brings all *givens*---including those resulting from extensions---into scope.

These rules have two main benefits:

Expand Down
2 changes: 1 addition & 1 deletion _overviews/scala3-book/ca-type-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ next-page: ca-multiversal-equality
A *type class* is an abstract, parameterized type that lets you add new behavior to any closed data type without using sub-typing.
This is useful in multiple use-cases, for example:

- Expressing how a type you don’t ownfrom the standard library or a third-party libraryconforms to such behavior
- Expressing how a type you don’t own---from the standard library or a third-party library---conforms to such behavior
- Expressing such a behavior for multiple types without involving sub-typing relationships between those types

In Scala 3, type classes are just traits with one or more parameters whose implementations are provided by `given` instances.
Expand Down
6 changes: 3 additions & 3 deletions _overviews/scala3-book/collections-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ As shown, `Map` and `Set` come in both immutable and mutable versions.

The basics of each type are demonstrated in the following sections.

> In Scala, a _buffer_such as `ArrayBuffer` and `ListBuffer`is a sequence that can grow and shrink.
> In Scala, a _buffer_---such as `ArrayBuffer` and `ListBuffer`---is a sequence that can grow and shrink.


### A note about immutable collections
Expand All @@ -75,7 +75,7 @@ With these types you don’t modify the collection; you apply functional methods

## Choosing a sequence

When choosing a _sequence_a sequential collection of elementsyou have two main decisions:
When choosing a _sequence_---a sequential collection of elements---you have two main decisions:

- Should the sequence be indexed (like an array), allowing rapid access to any element, or should it be implemented as a linear linked list?
- Do you want a mutable or immutable collection?
Expand Down Expand Up @@ -232,7 +232,7 @@ This works because a `List` is a singly-linked list that ends with the `Nil` ele
### Aside: The LazyList

The Scala collections also include a [LazyList](https://www.scala-lang.org/api/current/scala/collection/immutable/LazyList.html), which is a _lazy_ immutable linked list.
It’s called “lazy”or non-strictbecause it computes its elements only when they are needed.
It’s called “lazy”---or non-strict---because it computes its elements only when they are needed.

You can see how lazy a `LazyList` is in the REPL:

Expand Down
4 changes: 2 additions & 2 deletions _overviews/scala3-book/collections-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ a.find(_ > 20) // Some(30)
a.takeWhile(_ < 30) // List(10, 20)
```

It’s important to note that HOFs also accept methods and functions as parametersnot just lambda expressions.
It’s important to note that HOFs also accept methods and functions as parameters---not just lambda expressions.
Here are some examples of the `map` HOF that uses a method named `double`.
Several variations of the lambda syntax are shown again:

Expand Down Expand Up @@ -402,7 +402,7 @@ scala> a.reduce(_ * _)
res1: Int = 24
```

> An important concept to know about `reduce` is thatas its name impliesit’s used to _reduce_ a collection down to a single value.
> An important concept to know about `reduce` is that---as its name implies---it’s used to _reduce_ a collection down to a single value.



Expand Down
10 changes: 5 additions & 5 deletions _overviews/scala3-book/concurrency.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ next-page: scala-tools
---


When you want to write parallel and concurrent applications in Scala, you _can_ use the native Java `Thread`but the Scala [Future](https://www.scala-lang.org/api/current/scala/concurrent/Future$.html) offers a more high level and idiomatic approach so it’s preferred, and covered in this chapter.
When you want to write parallel and concurrent applications in Scala, you _can_ use the native Java `Thread`---but the Scala [Future](https://www.scala-lang.org/api/current/scala/concurrent/Future$.html) offers a more high level and idiomatic approach so it’s preferred, and covered in this chapter.



Expand All @@ -35,7 +35,7 @@ def aLongRunningTask(): Future[Int] = ???
val x = aLongRunningTask()
```

But the main difference in this case is that because `aLongRunningTask` takes an indeterminate amount of time to return, the value in `x` may or may not be _currently_ available, but it will be available at some point -- in the future.
But the main difference in this case is that because `aLongRunningTask` takes an indeterminate amount of time to return, the value in `x` may or may not be _currently_ available, but it will be available at some point---in the future.

Another way to look at this is in terms of blocking.
In this single-threaded example, the `println` statement isn’t printed until `aShortRunningTask` completes:
Expand All @@ -48,7 +48,7 @@ val x = aShortRunningTask()
println("Here")
```

Conversely, if `aShortRunningTask` is created as a `Future`, the `println` statement is printed almost immediately because `aShortRunningTask` is spawned off on some other thread -- it doesn’t block.
Conversely, if `aShortRunningTask` is created as a `Future`, the `println` statement is printed almost immediately because `aShortRunningTask` is spawned off on some other thread---it doesn’t block.

In this chapter you’ll see how to use futures, including how to run multiple futures in parallel and combine their results in a `for` expression.
You’ll also see examples of methods that are used to handle the value in a future once it returns.
Expand All @@ -62,7 +62,7 @@ You’ll also see examples of methods that are used to handle the value in a fut
## An example in the REPL

A future is used to create a temporary pocket of concurrency.
For instance, you use a future when you need to call an algorithm that runs an indeterminate amount of timesuch as calling a remote microserviceso you want to run it off of the main thread.
For instance, you use a future when you need to call an algorithm that runs an indeterminate amount of time---such as calling a remote microservice---so you want to run it off of the main thread.

To demonstrate how this works, let’s start with a `Future` example in the REPL.
First, paste in these required `import` statements:
Expand Down Expand Up @@ -252,7 +252,7 @@ Then, at 806 ms, the three futures complete and the code in the `yield` block is
Then the code immediately goes to the `Success` case in the `onComplete` method.

The 806 ms output is a key to seeing that the three futures are run in parallel.
If they were run sequentially, the total time would be about 1,400 msthe sum of the sleep times of the three futures.
If they were run sequentially, the total time would be about 1,400 ms---the sum of the sleep times of the three futures.
But because they’re run in parallel, the total time is just slightly longer than the longest-running future: `f1`, which is 800 ms.


Expand Down
6 changes: 3 additions & 3 deletions _overviews/scala3-book/control-structures.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ This is how the expression works:

1. The `for` expression starts to iterate over the values in the range `(10, 11, 12)`.
It first works on the value `10`, multiplies it by `2`, then _yields_ that result, the value `20`.
2. Next, it works on the `11`the second value in the range.
2. Next, it works on the `11`---the second value in the range.
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`.
Expand Down Expand Up @@ -443,7 +443,7 @@ i match

#### Case classes and match expressions

You can also extract fields from `case` classesand classes that have properly written `apply`/`unapply` methodsand use those in your guard conditions.
You can also extract fields from `case` classes---and classes that have properly written `apply`/`unapply` methods---and use those in your guard conditions.
Here’s an example using a simple `Person` case class:

```scala
Expand All @@ -470,7 +470,7 @@ def isTruthy(a: Matchable) = a match
case _ => true
```

The input parameter `a` is defined to be the [`Matchable` type][matchable]which is the root of all Scala types that pattern matching can be performed on.
The input parameter `a` is defined to be the [`Matchable` type][matchable]---which is the root of all Scala types that pattern matching can be performed on.
The method is implemented by matching on the input, providing two cases:
The first one checks whether the given value is either the integer `0` or an empty string and returns `false` in this case.
In the default case, we return `true` for any other value.
Expand Down
8 changes: 4 additions & 4 deletions _overviews/scala3-book/domain-modeling-fp.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ case class Order(
#### “Skinny domain objects”

In his book, *Functional and Reactive Domain Modeling*, Debasish Ghosh states that where OOP practitioners describe their classes as “rich domain models” that encapsulate data and behaviors, FP data models can be thought of as “skinny domain objects.”
This is becauseas this lesson showsthe data models are defined as `case` classes with attributes, but no behaviors, resulting in short and concise data structures.
This is because---as this lesson shows---the data models are defined as `case` classes with attributes, but no behaviors, resulting in short and concise data structures.



Expand Down Expand Up @@ -221,7 +221,7 @@ These different solutions are shown in the remainder of this section.

### Companion Object

A first approach is to define the behaviorthe functionsin a companion object.
A first approach is to define the behavior---the functions---in a companion object.

> As discussed in the Domain Modeling [Tools section][modeling-tools], a _companion object_ is an `object` that has the same name as a class, and is declared in the same file as the class.

Expand Down Expand Up @@ -292,7 +292,7 @@ trait PizzaServiceInterface:
def updateCrustType(p: Pizza, ct: CrustType): Pizza
```

As shown, each method takes a `Pizza` as an input parameteralong with other parametersand then returns a `Pizza` instance as a result
As shown, each method takes a `Pizza` as an input parameter---along with other parameters---and then returns a `Pizza` instance as a result

When you write a pure interface like this, you can think of it as a contract that states, “all non-abstract classes that extend this trait *must* provide an implementation of these services.”

Expand All @@ -309,7 +309,7 @@ val p3 = updateCrustType(p2, Thick)
val p4 = updateCrustSize(p3, Large)
```

If that code seems okay, you’ll typically start sketching another APIsuch as an API for ordersbut since we’re only looking at pizzas right now, we’ll stop thinking about interfaces and create a concrete implementation of this interface.
If that code seems okay, you’ll typically start sketching another API---such as an API for orders---but since we’re only looking at pizzas right now, we’ll stop thinking about interfaces and create a concrete implementation of this interface.

> Notice that this is usually a two-step process.
> In the first step, you sketch the contract of your API as an *interface*.
Expand Down
10 changes: 5 additions & 5 deletions _overviews/scala3-book/domain-modeling-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class Person:
defining the two fields `name` and `vocation` together with a constructor that accepts values for the 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 immutableread onlycreate them as `val` fields instead.
If you want them to be immutable---read only---create them as `val` fields instead.

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

Expand Down Expand Up @@ -297,7 +297,7 @@ Companion objects can be used for several purposes:
- As shown, they can be used to group “static” methods under a namespace
- These methods can be public or private
- If `calculateArea` was public, it would be accessed as `Circle.calculateArea`
- They can contain `apply` methods, whichthanks to some syntactic sugarwork as factory methods to construct new instances
- They can contain `apply` methods, which---thanks to some syntactic sugar---work as factory methods to construct new instances
- They can contain `unapply` methods, which are used to deconstruct objects, such as with pattern matching

Here’s a quick look at how `apply` methods that can be used as factory methods to create new objects:
Expand Down Expand Up @@ -352,7 +352,7 @@ trait Employee:
def lastName: String
```
However, traits can also contain concrete members.
For instance, the following trait defines two abstract members`numLegs` and `walk()`and also has a concrete implementation of a `stop()` method:
For instance, the following trait defines two abstract members---`numLegs` and `walk()`---and also has a concrete implementation of a `stop()` method:

```scala
trait HasLegs:
Expand Down Expand Up @@ -514,7 +514,7 @@ enum Color extends Enum[Color] { case Red, Green, Blue }
```

The type parameter comes from the Java `enum` definition, and should be the same as the type of the enum.
There’s no need to provide constructor arguments (as defined in the Java API docs) to `java.lang.Enum` when extending itthe compiler generates them automatically.
There’s no need to provide constructor arguments (as defined in the Java API docs) to `java.lang.Enum` when extending it---the compiler generates them automatically.

After defining `Color` like that, you can use it like you would a Java enum:

Expand Down Expand Up @@ -603,7 +603,7 @@ case class Student(name: String, year: Int) extends Person
case class Teacher(name: String, specialty: String) extends Person
```

Because those are defined as case classesand they have built-in `unapply` methodsyou can write a match expression like this:
Because those are defined as case classes---and they have built-in `unapply` methods---you can write a match expression like this:

```scala
def getPrintableString(p: Person): String = p match
Expand Down
6 changes: 3 additions & 3 deletions _overviews/scala3-book/first-look-at-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ val d: Double = 2.0
val f: Float = 3.0
```

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.
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:
Expand All @@ -112,7 +112,7 @@ val s = "Bill"
val c = 'a'
```

As shown, enclose strings in double-quotesor triple-quotes for multiline stringsand enclose a character in single-quotes.
As shown, enclose strings in double-quotes---or triple-quotes for multiline strings---and enclose a character in single-quotes.

Those data types and their ranges are:

Expand Down Expand Up @@ -263,7 +263,7 @@ This will be covered later in the tour.

`Nothing` is a subtype of all types, also called the **bottom type**.
There is no value that has the type `Nothing`.
A common use is to signal non-termination, such as a thrown exception, program exit, or an infinite loopi.e., it is the type of an expression which does not evaluate to a value, or a method that does not return normally.
A common use is to signal non-termination, such as a thrown exception, program exit, or an infinite loop---i.e., it is the type of an expression which does not evaluate to a value, or a method that does not return normally.

`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`.
Expand Down
4 changes: 2 additions & 2 deletions _overviews/scala3-book/fp-functional-error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ In this example, if `x` can be converted to an `Int`, the first `case` statement

## Using a `for` expression

Another common solution is to use a `for` expressioni.e., the `for`/`yield` combination that was shown earlier in this book.
Another common solution is to use a `for` expression---i.e., the `for`/`yield` combination that was shown earlier in this book.
For instance, imagine that you want to convert three strings to integer values, and then add them together.
This is how you do that with a `for` expression and `makeInt`:

Expand Down Expand Up @@ -267,7 +267,7 @@ val santa = new Address(
```

Historically, developers have used blank strings and null values in this situation, both of which are hacks to work around the root problem: `street2` is an *optional* field.
In Scalaand other modern languagesthe correct solution is to declare up front that `street2` is optional:
In Scala---and other modern languages---the correct solution is to declare up front that `street2` is optional:

```scala
class Address:
Expand Down
2 changes: 1 addition & 1 deletion _overviews/scala3-book/fp-functions-are-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ In most scenarios it doesn’t matter if `double` is a function or a method; Sca
Behind the scenes, the Scala technology that lets you treat methods just like functions is known as [Eta Expansion][eta].

This ability to seamlessly pass functions around as variables is a distinguishing feature of functional programming languages like Scala.
And as you’ve seen in the `map` and `filter` examples throughout this book, the ability to pass functions into other functions helps you create code that is concise and still readable*expressive*.
And as you’ve seen in the `map` and `filter` examples throughout this book, the ability to pass functions into other functions helps you create code that is concise and still readable---*expressive*.

If you’re not comfortable with the process of passing functions as parameters into other functions, here are a few more examples you can experiment with:

Expand Down
2 changes: 1 addition & 1 deletion _overviews/scala3-book/fp-immutable-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This is where higher-order functions like `map` and `filter` come in.
TODO: need a better example
{% endcomment %}

For example, imagine that you have a list of namesa `List[String]`that are all in lowercase, and you want to find all the names that begin with the letter `"j"`, and then you want to capitalize those names.
For example, imagine that you have a list of names---a `List[String]`---that are all in lowercase, and you want to find all the names that begin with the letter `"j"`, and then you want to capitalize those names.
In FP you write this code:

```scala
Expand Down
2 changes: 1 addition & 1 deletion _overviews/scala3-book/fp-intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ next-page: fp-what-is-fp
---


Scala lets you write code in an object-oriented programming (OOP) style, a functional programming (FP) style, and also in a hybrid styleusing both approaches in combination.
Scala lets you write code in an object-oriented programming (OOP) style, a functional programming (FP) style, and also in a hybrid style---using both approaches in combination.
[As Martin Odersky has stated](https://twitter.com/alexelcu/status/996408359514525696), the essence of Scala is a fusion of functional and object-oriented programming in a typed setting:

- Functions for the logic
Expand Down
2 changes: 1 addition & 1 deletion _overviews/scala3-book/fp-pure-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ If you understand that code, you’ll see that it meets the pure function defini
The first key point of this section is the definition of a pure function:

> A *pure function* is a function that depends only on its declared inputs and its internal algorithm to produce its output.
> It does not read any other values from “the outside world”the world outside of the function’s scopeand it doesn’t modify any values in the outside world.
> It does not read any other values from “the outside world”---the world outside of the function’s scope---and it doesn’t modify any values in the outside world.

A second key point is that every real-world application interacts with the outside world.
Therefore, a simplified way to think about functional programs is that they consist of a core of pure functions that are wrapped with other functions that interact with the outside world.
Expand Down
Loading