Skip to content

Commit e2a35af

Browse files
committed
adjust formatting
1 parent 134df43 commit e2a35af

File tree

1 file changed

+81
-48
lines changed

1 file changed

+81
-48
lines changed

_overviews/scala3-book/domain-modeling-tools.md

Lines changed: 81 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ val p = new Person("Robert Allen Zimmerman", "Harmonica Player")
5757
{% endtab %}
5858
{% endtabs %}
5959

60-
However, with [creator applications][creator] this isn’t required in Scala 3:
60+
However, with [universal apply methods][creator] this isn’t required in Scala 3:
6161

6262
{% tabs class_3 %}
6363
{% tab 'Scala 3 Only' for=class_3 %}
@@ -144,7 +144,21 @@ class Person(var firstName: String, var lastName: String):
144144

145145
The following REPL session shows how to create a new `Person` instance with this class:
146146

147+
{% tabs demo-person class=tabs-scala-version %}
148+
{% tab 'Scala 2' for=demo-person %}
149+
````scala
150+
scala> val john = new Person("John", "Doe")
151+
initialization begins
152+
John Doe
153+
initialization ends
154+
val john: Person = Person@55d8f6bb
155+
156+
scala> john.printFullName
157+
John Doe
147158
````
159+
{% endtab %}
160+
{% tab 'Scala 3' for=demo-person %}
161+
````scala
148162
scala> val john = Person("John", "Doe")
149163
initialization begins
150164
John Doe
@@ -154,6 +168,8 @@ val john: Person = Person@55d8f6bb
154168
scala> john.printFullName
155169
John Doe
156170
````
171+
{% endtab %}
172+
{% endtabs %}
157173

158174
Classes can also extend traits and abstract classes, which we cover in dedicated sections below.
159175

@@ -184,8 +200,19 @@ class Socket(val timeout: Int = 5_000, val linger: Int = 5_000):
184200

185201
A great thing about this feature is that it lets consumers of your code create classes in a variety of different ways, as though the class had alternate constructors:
186202

187-
{% tabs default-values_2 %}
188-
{% tab 'Scala 2 and 3' for=default-values_2 %}
203+
{% tabs default-values_2 class=tabs-scala-version %}
204+
{% tab 'Scala 2' for=default-values_2 %}
205+
206+
```scala
207+
val s = new Socket() // timeout: 5000, linger: 5000
208+
val s = new Socket(2_500) // timeout: 2500, linger: 5000
209+
val s = new Socket(10_000, 10_000) // timeout: 10000, linger: 10000
210+
val s = new Socket(timeout = 10_000) // timeout: 10000, linger: 5000
211+
val s = new Socket(linger = 10_000) // timeout: 5000, linger: 10000
212+
```
213+
214+
{% endtab %}
215+
{% tab 'Scala 3' for=default-values_2 %}
189216

190217
```scala
191218
val s = Socket() // timeout: 5000, linger: 5000
@@ -201,8 +228,22 @@ val s = Socket(linger = 10_000) // timeout: 5000, linger: 10000
201228
When creating a new instance of a class, you can also use named parameters.
202229
This is particularly helpful when many of the parameters have the same type, as shown in this comparison:
203230

204-
{% tabs default-values_3 %}
205-
{% tab 'Scala 2 and 3' for=default-values_3 %}
231+
{% tabs default-values_3 class=tabs-scala-version %}
232+
{% tab 'Scala 2' for=default-values_3 %}
233+
234+
```scala
235+
// option 1
236+
val s = new Socket(10_000, 10_000)
237+
238+
// option 2
239+
val s = new Socket(
240+
timeout = 10_000,
241+
linger = 10_000
242+
)
243+
```
244+
245+
{% endtab %}
246+
{% tab 'Scala 3' for=default-values_3 %}
206247

207248
```scala
208249
// option 1
@@ -254,7 +295,7 @@ class Student(
254295
this(name, govtId)
255296
_applicationDate = Some(applicationDate)
256297
}
257-
298+
258299
// [3] a constructor for when the student is approved
259300
// and now has a student id
260301
def this(
@@ -481,15 +522,15 @@ For instance, in the following example the class `Circle` has a member named `ar
481522
```scala
482523
import scala.math._
483524

484-
case class Circle(radius: Double) {
525+
class Circle(val radius: Double) {
485526
def area: Double = Circle.calculateArea(radius)
486527
}
487528

488529
object Circle {
489530
private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
490531
}
491532

492-
val circle1 = Circle(5.0)
533+
val circle1 = new Circle(5.0)
493534
circle1.area
494535
```
495536

@@ -500,7 +541,7 @@ circle1.area
500541
```scala
501542
import scala.math.*
502543

503-
case class Circle(radius: Double):
544+
class Circle(val radius: Double):
504545
def area: Double = Circle.calculateArea(radius)
505546

506547
object Circle:
@@ -546,7 +587,7 @@ object Person {
546587
p.name = name
547588
p
548589
}
549-
590+
550591
// a two-arg factory method
551592
def apply(name: String, age: Int): Person = {
552593
var p = new Person
@@ -563,6 +604,8 @@ val fred = Person("Fred", 29)
563604
//val fred: Person = Fred is 29 years old
564605
```
565606

607+
The `unapply` method isn’t covered here, but it’s covered in the [Language Specification](https://scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#extractor-patterns).
608+
566609
{% endtab %}
567610

568611
{% tab 'Scala 3' for=companion-use %}
@@ -597,11 +640,11 @@ val fred = Person("Fred", 29)
597640
//val fred: Person = Fred is 29 years old
598641
```
599642

643+
The `unapply` method isn’t covered here, but it’s covered in the [Reference documentation]({{ site.scala3ref }}/changed-features/pattern-matching.html).
644+
600645
{% endtab %}
601646
{% endtabs %}
602647

603-
The `unapply` method isn’t covered here, but it’s covered in the [Reference documentation][unapply].
604-
605648
## Traits
606649

607650
If you’re familiar with Java, a Scala trait is similar to an interface in Java 8+. Traits can contain:
@@ -700,7 +743,7 @@ Later in your code, classes can mix multiple traits to build larger components:
700743
{% tab 'Scala 2' for=traits_4 %}
701744

702745
```scala
703-
class IrishSetter(name: String) extends HasLegs, HasTail {
746+
class IrishSetter(name: String) extends HasLegs with HasTail {
704747
val numLegs = 4
705748
val tailColor = "Red"
706749
def walk() = println("I’m walking")
@@ -726,8 +769,15 @@ class IrishSetter(name: String) extends HasLegs, HasTail:
726769
Notice that the `IrishSetter` class implements the abstract members that are defined in `HasLegs` and `HasTail`.
727770
Now you can create new `IrishSetter` instances:
728771

729-
{% tabs traits_5 %}
730-
{% tab 'Scala 2 and 3' for=traits_5 %}
772+
{% tabs traits_5 class=tabs-scala-version %}
773+
{% tab 'Scala 2' for=traits_5 %}
774+
775+
```scala
776+
val d = new IrishSetter("Big Red") // "Big Red is a Dog"
777+
```
778+
779+
{% endtab %}
780+
{% tab 'Scala 3' for=traits_5 %}
731781

732782
```scala
733783
val d = IrishSetter("Big Red") // "Big Red is a Dog"
@@ -775,7 +825,7 @@ class Dog(name: String, var age: Int) extends Pet(name) {
775825
val greeting = "Woof"
776826
}
777827

778-
val d = Dog("Fido", 1)
828+
val d = new Dog("Fido", 1)
779829
```
780830

781831
{% endtab %}
@@ -799,26 +849,9 @@ val d = Dog("Fido", 1)
799849

800850
However, with Scala 3, traits can now have [parameters][trait-params], so you can now use traits in the same situation:
801851

802-
{% tabs abstract_2 class=tabs-scala-version %}
803-
{% tab 'Scala 2' for=abstract_2 %}
804-
805-
```scala
806-
trait Pet(name: String) {
807-
def greeting: String
808-
def age: Int
809-
override def toString = s"My name is $name, I say $greeting, and I’m $age"
810-
}
811-
812-
class Dog(name: String, var age: Int) extends Pet(name) {
813-
val greeting = "Woof"
814-
}
815-
816-
val d = Dog("ssssssss
817-
```
818-
819-
{% endtab %}
852+
{% tabs abstract_2 %}
820853

821-
{% tab 'Scala 3' for=abstract_2 %}
854+
{% tab 'Scala 3 Only' for=abstract_2 %}
822855

823856
```scala
824857
trait Pet(name: String):
@@ -875,18 +908,18 @@ val currentCrustSize = Small
875908
{% endtab %}
876909
{% endtabs %}
877910

878-
Enum values can be compared using equals (`==`), and also enum_1ed on:
911+
Enum values can be compared using equals (`==`), and also matched on:
879912

880913
{% tabs enum_3 %}
881914
{% tab 'Scala 3 Only' for=enum_3 %}
882915

883916
```scala
884917
// if/then
885-
if (currentCrustSize == Large)
918+
if currentCrustSize == Large then
886919
println("You get a prize!")
887920

888-
// enum_1
889-
currentCrustSize enum_1
921+
// match
922+
currentCrustSize match
890923
case Small => println("small")
891924
case Medium => println("medium")
892925
case Large => println("large")
@@ -1000,7 +1033,7 @@ christina.name = "Fred" // error: reassignment to val
10001033

10011034
Since the fields of a case class are assumed to be immutable, the Scala compiler can generate many helpful methods for you:
10021035

1003-
- An `unapply` method is generated, which allows you to perform pattern case-classes_1ing on a case class (that is, `case Person(n, r) => ...`).
1036+
- An `unapply` method is generated, which allows you to perform pattern matching on a case class (that is, `case Person(n, r) => ...`).
10041037
- A `copy` method is generated in the class, which is very useful to create modified copies of an instance.
10051038
- `equals` and `hashCode` methods using structural equality are generated, allowing you to use instances of case classes in `Map`s.
10061039
- A default `toString` method is generated, which is helpful for debugging.
@@ -1038,7 +1071,7 @@ val cubs2016 = cubs1908.copy(lastWorldSeriesWin = 2016)
10381071

10391072
```scala
10401073
// Case classes can be used as patterns
1041-
christina match:
1074+
christina match
10421075
case Person(n, r) => println("name is " + n)
10431076

10441077
// `equals` and `hashCode` methods generated for you
@@ -1068,7 +1101,7 @@ As mentioned, case classes support functional programming (FP):
10681101
Since instances of case classes can’t be changed, they can easily be shared without fearing mutation or race conditions.
10691102
- Instead of mutating an instance, you can use the `copy` method as a template to create a new (potentially changed) instance.
10701103
This process can be referred to as “update as you copy.”
1071-
- Having an `unapply` method auto-generated for you also lets case classes be used in advanced ways with pattern case-classes_1ing.
1104+
- Having an `unapply` method auto-generated for you also lets case classes be used in advanced ways with pattern matching.
10721105

10731106
{% comment %}
10741107
NOTE: We can use this following text, if desired. If it’s used, it needs to be updated a little bit.
@@ -1113,7 +1146,7 @@ case class Teacher(name: String, specialty: String) extends Person
11131146
{% endtab %}
11141147
{% endtabs %}
11151148

1116-
Because those are defined as case classes---and they have built-in `unapply` methods---you can write a case-classes_1 expression like this:
1149+
Because those are defined as case classes---and they have built-in `unapply` methods---you can write a match expression like this:
11171150

11181151
{% tabs case-classes_7 class=tabs-scala-version %}
11191152
{% tab 'Scala 2' for=case-classes_7 %}
@@ -1156,7 +1189,7 @@ case Teacher(name, whatTheyTeach) =>
11561189
{% endtabs %}
11571190

11581191
Those patterns work because `Student` and `Teacher` are defined as case classes that have `unapply` methods whose type signature conforms to a certain standard.
1159-
Technically, the specific type of pattern case-classes_1ing shown in these examples is known as a _constructor pattern_.
1192+
Technically, the specific type of pattern matching shown in these examples is known as a _constructor pattern_.
11601193

11611194
> The Scala standard is that an `unapply` method returns the case class constructor fields in a tuple that’s wrapped in an `Option`.
11621195
> The “tuple” part of the solution was shown in the previous lesson.
@@ -1192,9 +1225,9 @@ res1: String = Bob Donnan teaches Mathematics.
11921225

11931226
> All of this content on `unapply` methods and extractors is a little advanced for an introductory book like this, but because case classes are an important FP topic, it seems better to cover them, rather than skipping over them.
11941227
1195-
#### Add pattern case-classes_1ing to any type with unapply
1228+
#### Add pattern matching to any type with unapply
11961229

1197-
A great Scala feature is that you can add pattern case-classes_1ing to any type by writing your own `unapply` method.
1230+
A great Scala feature is that you can add pattern matching to any type by writing your own `unapply` method.
11981231
As an example, this class defines an `unapply` method in its companion object:
11991232

12001233
{% tabs case-classes_11 class=tabs-scala-version %}
@@ -1220,7 +1253,7 @@ object Person:
12201253
{% endtab %}
12211254
{% endtabs %}
12221255

1223-
Because it defines an `unapply` method, and because that method returns a tuple, you can now use `Person` with a `case-classes_1` expression:
1256+
Because it defines an `unapply` method, and because that method returns a tuple, you can now use `Person` with a `match` expression:
12241257

12251258
{% tabs case-classes_12 class=tabs-scala-version %}
12261259
{% tab 'Scala 2' for=case-classes_12 %}
@@ -1277,7 +1310,7 @@ case object StopPlaying extends Message
12771310
{% endtab %}
12781311
{% endtabs %}
12791312

1280-
Then in other parts of your code, you can write methods like this, which use pattern case-objects_1ing to handle the incoming message (assuming the methods `playSong`, `changeVolume`, and `stopPlayingSong` are defined somewhere else):
1313+
Then in other parts of your code, you can write methods like this, which use pattern matching to handle the incoming message (assuming the methods `playSong`, `changeVolume`, and `stopPlayingSong` are defined somewhere else):
12811314

12821315
{% tabs case-objects_2 class=tabs-scala-version %}
12831316
{% tab 'Scala 2' for=case-objects_2 %}

0 commit comments

Comments
 (0)