Skip to content

Updated pages to be “Scala 3 Only” #2689

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 3 commits into from
Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
26 changes: 26 additions & 0 deletions _overviews/scala3-book/ca-context-bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ num: 61
previous-page: ca-given-using-clauses
next-page: ca-given-imports
---
<span class="tag tag-inline">Scala 3 only</span>


{% comment %}
Expand All @@ -22,29 +23,54 @@ In that case you don’t have to define a parameter name, and can just provide t

For example, this `maximum` method takes a _context parameter_ of type `Ord`, only to pass it on as an argument to `max`:

{% tabs context-bounds-max-named-param %}

{% tab 'Scala 3 Only' %}

```scala
def maximum[A](xs: List[A])(using ord: Ord[A]): A =
xs.reduceLeft(max(ord))
```

{% endtab %}

{% endtabs %}

In that code the parameter name `ord` isn’t actually required; it can be passed on as an inferred argument to `max`, so you just state that `maximum` uses the type `Ord[A]` without giving it a name:

{% tabs context-bounds-no-param-name %}

{% tab 'Scala 3 Only' %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok so anonymous context parameter truly is a scala 3 only thing, so if you add Scala 2 tab to context-bounds-max-named-param, then this paragraph and snippet can go in the scala 3 tab there (i.e. drop the context-bounds-no-param-name tabs).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve removed this example from the ca-context-bounds.md file because I don’t think it should be part of that file. Instead, I think we should move it to the file ca-given-using-clauses.md.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, maybe it’s better to have it in this file. If you think it should be here, let me know and I’ll update it.


```scala
def maximum[A](xs: List[A])(using Ord[A]): A =
xs.reduceLeft(max)
```

{% endtab %}

{% endtabs %}


## Context bounds

Given that background, a _context bound_ is a shorthand syntax for expressing the pattern of, “a context parameter that depends on a type parameter.”

Using a context bound, the `maximum` method can be written like this:

{% tabs context-bounds-max-rewritten %}

{% tab 'Scala 3 Only' %}

```scala
def maximum[A: Ord](xs: List[A]): A = xs.reduceLeft(max)
```

{% endtab %}

{% endtabs %}


A bound like `: Ord` on a type parameter `A` of a method or class indicates a context parameter with `Ord[A]`.

For more information about context bounds, see the [“What are context bounds?”](https://docs.scala-lang.org/tutorials/FAQ/context-bounds.html) section of the Scala FAQ.
17 changes: 17 additions & 0 deletions _overviews/scala3-book/ca-given-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ num: 62
previous-page: ca-context-bounds
next-page: ca-type-classes
---
<span class="tag tag-inline">Scala 3 only</span>


To make it more clear where givens in the current scope are coming from, a special form of the `import` statement is used to import `given` instances.
The basic form is shown in this example:

{% tabs given-imports-basic-form %}

{% tab 'Scala 3 Only' %}

```scala
object A:
class TC
Expand All @@ -23,15 +28,27 @@ object B:
import A.given // import the given instance
```

{% endtab %}

{% endtabs %}

In this code the `import A.*` clause of object `B` imports all members of `A` *except* the `given` instance, `tc`.
Conversely, the second import, `import A.given`, imports *only* that `given` instance.
The two `import` clauses can also be merged into one:

{% tabs given-imports-merged %}

{% tab 'Scala 3 Only' %}

```scala
object B:
import A.{given, *}
```

{% endtab %}

{% endtabs %}


## Discussion

Expand Down
49 changes: 49 additions & 0 deletions _overviews/scala3-book/ca-multiversal-equality.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ num: 64
previous-page: ca-type-classes
next-page: ca-implicit-conversions
---
<span class="tag tag-inline">Scala 3 only</span>


Previously, Scala had *universal equality*: Two values of any types could be compared with each other using `==` and `!=`.
Expand Down Expand Up @@ -44,6 +45,10 @@ d == c // false, but it compiles
But with Scala 3 you can disable such comparisons.
By (a) importing `scala.language.strictEquality` or (b) using the `-language:strictEquality` compiler flag, this comparison no longer compiles:

{% tabs multiversal-equality-strictEquality %}

{% tab 'Scala 3 Only' %}

```scala
import scala.language.strictEquality

Expand All @@ -55,25 +60,45 @@ println(rover == fido) // compiler error
// Values of types Dog and Dog cannot be compared with == or !=
```

{% endtab %}

{% endtabs %}


## Enabling comparisons

There are two ways to enable this comparison using the Scala 3 `CanEqual` type class.
For simple cases like this, your class can *derive* the `CanEqual` class:

{% tabs multiversal-equality-derives-CanEqual %}

{% tab 'Scala 3 Only' %}

```scala
// Option 1
case class Dog(name: String) derives CanEqual
```

{% endtab %}

{% endtabs %}

As you’ll see in a few moments, when you need more flexibility you can also use this syntax:

{% tabs multiversal-equality-given-CanEqual %}

{% tab 'Scala 3 Only' %}

```scala
// Option 2
case class Dog(name: String)
given CanEqual[Dog, Dog] = CanEqual.derived
```

{% endtab %}

{% endtabs %}

Either of those two approaches now let `Dog` instances to be compared to each other.


Expand All @@ -82,11 +107,19 @@ Either of those two approaches now let `Dog` instances to be compared to each ot
In a more real-world example, imagine you have an online bookstore and want to allow or disallow the comparison of physical, printed books, and audiobooks.
With Scala 3 you start by enabling multiversal equality as shown in the previous example:

{% tabs multiversal-equality-strictEquality-2 %}

{% tab 'Scala 3 Only' %}

```scala
// [1] add this import, or this command line flag: -language:strictEquality
import scala.language.strictEquality
```

{% endtab %}

{% endtabs %}

Then create your domain objects as usual:

```scala
Expand All @@ -113,6 +146,10 @@ case class AudioBook(

Finally, use `CanEqual` to define which comparisons you want to allow:

{% tabs multiversal-equality-CanEqual-allow-comps %}

{% tab 'Scala 3 Only' %}

```scala
// [3] create type class instances to define the allowed comparisons.
// allow `PrintedBook == PrintedBook`
Expand All @@ -131,6 +168,10 @@ val aBook = AudioBook("1984", "George Orwell", 2006, 682)
println(pBook == aBook) // compiler error
```

{% endtab %}

{% endtabs %}

The last line of code results in this compiler error message:

````
Expand All @@ -145,12 +186,20 @@ This is how multiversal equality catches illegal type comparisons at compile tim
That works as desired, but in some situations you may want to allow the comparison of physical books to audiobooks.
When you want this, create these two additional equality comparisons:

{% tabs multiversal-equality-additional-comps %}

{% tab 'Scala 3 Only' %}

```scala
// allow `PrintedBook == AudioBook`, and `AudioBook == PrintedBook`
given CanEqual[PrintedBook, AudioBook] = CanEqual.derived
given CanEqual[AudioBook, PrintedBook] = CanEqual.derived
```

{% endtab %}

{% endtabs %}

Now you can compare physical books to audiobooks without a compiler error:

```scala
Expand Down