You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Scala supports the notion of _case classes_. Case classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via [pattern matching](pattern-matching.html).
13
+
Scala supports the notion of _case classes_. Case classes are just regular classes that are:
14
14
15
-
Here is an example for a class hierarchy which consists of an abstract super class `Term` and three concrete case classes `Var`, `Fun`, and `App`.
15
+
* Immutable by default
16
+
* Decomposable through [pattern matching](pattern-matching.html)
17
+
* Compared by structural equality instead of by reference
18
+
* Succinct to instantiate and operate on
19
+
20
+
Here is an example for a Notification type hierarchy which consists of an abstract super class `Notification` and three concrete Notification types implemented with case classes `Email`, `SMS`, and `VoiceRecording`.
16
21
17
22
```tut
18
-
abstract class Term
19
-
case class Var(name: String) extends Term
20
-
case class Fun(arg: String, body: Term) extends Term
21
-
case class App(f: Term, v: Term) extends Term
23
+
abstract class Notification
24
+
case class Email(sourceEmail: String, title: String, body: String) extends Notification
25
+
case class SMS(sourceNumber: String, message: String) extends Notification
26
+
case class VoiceRecording(contactName: String, link: String) extends Notification
22
27
```
23
28
24
-
This class hierarchy can be used to represent terms of the [untyped lambda calculus](https://en.wikipedia.org/wiki/Lambda_calculus). To facilitate the construction of case class instances, Scala does not require that the `new` primitive is used. One can simply use the class name as a function.
29
+
Instantiating a case class is easy: (Note that we don't need to use the `new` keyword)
30
+
31
+
```tut
32
+
val emailFromJohn = Email("[email protected]", "Greetings From John!", "Hello World!")
33
+
```
25
34
26
-
Here is an example:
35
+
The constructor parameters of case classes are treated as public values and can be accessed directly.
27
36
28
37
```tut
29
-
Fun("x", Fun("y", App(Var("x"), Var("y"))))
38
+
val title = emailFromJohn.title
39
+
println(title) // prints "Greetings From John!"
40
+
```
41
+
42
+
With case classes, you cannot mutate their fields directly. (unless you insert `var` before a field, but doing so is generally discouraged).
43
+
44
+
```tut:fail
45
+
emailFromJohn.title = "Goodbye From John!" // This is a compilation error. We cannot assign another value to val fields, which all case classes fields are by default.
30
46
```
31
47
32
-
The constructor parameters of case classes are treated as public values and can be accessed directly.
48
+
Instead, you make a copy using the `copy` method. As seen below, you can replace just some of the fields:
33
49
34
50
```tut
35
-
val x = Var("x")
36
-
println(x.name)
51
+
val editedEmail = emailFromJohn.copy(title = "I am learning Scala!", body = "It's so cool!")
52
+
53
+
println(emailFromJohn) // prints "Email([email protected],Greetings From John!,Hello World!)"
54
+
println(editedEmail) // prints "Email([email protected],I am learning Scala,It's so cool!)"
37
55
```
38
56
39
57
For every case class the Scala compiler generates an `equals` method which implements structural equality and a `toString` method. For instance:
It only makes sense to define case classes if pattern matching is used to decompose data structures. The following [object](singleton-objects.html) defines a pretty printer function for our lambda calculus representation:
77
+
With case classes, you can utilize **pattern matching** to work with your data. Here's a function that prints out different messages depending on what type of Notification is received:
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
120
+
val specialEmail = Email("[email protected]", "Drinks tonight?", "I'm free after 5!")
121
+
val specialSms = SMS("55555", "I'm here! Where are you?")
122
+
123
+
// prints:
124
+
// You got an SMS from 12345! Message: Are you there?
125
+
// you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
126
+
// You got an email from special someone!
127
+
// You got an SMS from special someone!
128
+
86
129
```
87
130
88
-
In our example, the function `printTerm` is expressed as a pattern matching statement starting with the `match` keyword and consisting of sequences of `case Pattern => Body` clauses.
89
-
The program above also defines a function `isIdentityFun` which checks if a given term corresponds to a simple identity function. This example uses deep patterns and guards. After matching a pattern with a given value, the guard (defined after the keyword `if`) is evaluated. If it returns `true`, the match succeeds; otherwise, it fails and the next pattern will be tried.
131
+
When programming in Scala, it is recommended that you use case classes pervasively to model/group data as they help you to write more expressive and maintainable code:
132
+
133
+
* Immutability frees you from needing to keep track of where and when things are mutated
134
+
* Comparison-by-value allows you compare instances as if they are primitive values - no more uncertainty regarding whether instances of a class is compared by value or reference
135
+
* Pattern matching simplifies branching logic, which leads to less bugs and more readable code.
0 commit comments