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
Copy file name to clipboardExpand all lines: _overviews/core/value-classes.md
+23-15Lines changed: 23 additions & 15 deletions
Original file line number
Diff line number
Diff line change
@@ -64,7 +64,7 @@ For example, a fragment of a data type that represents a distance might look lik
64
64
def +(m: Meter): Meter = new Meter(value + m.value)
65
65
}
66
66
67
-
Code that adds two distances, such as
67
+
Code that adds two distances, such as:
68
68
69
69
val x = new Meter(3.4)
70
70
val y = new Meter(4.3)
@@ -93,7 +93,7 @@ Whenever a value class is treated as another type, including a universal trait,
93
93
As an example, consider the `Meter` value class:
94
94
95
95
trait Distance extends Any
96
-
case class Meter(val value: Double) extends AnyVal with Distance
96
+
case class Meter(value: Double) extends AnyVal with Distance
97
97
98
98
A method that accepts a value of type `Distance` will require an actual `Meter` instance.
99
99
In the following example, the `Meter` classes are actually instantiated:
@@ -107,7 +107,7 @@ If the signature of `add` were instead:
107
107
108
108
then allocations would not be necessary.
109
109
Another instance of this rule is when a value class is used as a type argument.
110
-
For example, the actual Meter instance must be created for even a call to identity:
110
+
For example, the actual Meter instance must be created for even a call to `identity`:
111
111
112
112
def identity[T](t: T): T = t
113
113
identity(Meter(5.0))
@@ -122,12 +122,12 @@ The array here contains actual `Meter` instances and not just the underlying dou
122
122
123
123
Lastly, type tests such as those done in pattern matching or `asInstanceOf` require actual value class instances:
124
124
125
-
case class P(val i: Int) extends AnyVal
125
+
case class P(i: Int) extends AnyVal
126
126
127
-
val p = new P(3)
127
+
val p = P(3)
128
128
p match { // new P instantiated here
129
129
case P(3) => println("Matched 3")
130
-
case P(x) => println("Not 3")
130
+
case P(_) => println("Not 3")
131
131
}
132
132
133
133
## Limitations
@@ -141,15 +141,15 @@ A value class ...
141
141
142
142
1. ... must have only a primary constructor with exactly one public, val parameter whose type is not a user-defined value class. (From Scala 2.11.0, the parameter may be non-public.)
143
143
2. ... may not have `@specialized` type parameters.
144
-
3. ... may not have nested or local classes, traits, or objects
144
+
3. ... may not have nested or local classes, traits, or objects.
145
145
4. ... may not define concrete `equals` or `hashCode` methods.
146
-
5. ... must be a top-level class or a member of a statically accessible object
146
+
5. ... must be a top-level class or a member of a statically accessible object.
147
147
6. ... can only have defs as members. In particular, it cannot have lazy vals, vars, or vals as members.
148
148
7. ... cannot be extended by another class.
149
149
150
150
### Examples of Limitations
151
151
152
-
This section provides many concrete consequences of these limitations not already described in the necessary allocations section.
152
+
This section provides many concrete examples of the limitations already described in the previous section.
153
153
154
154
Multiple constructor parameters are not allowed:
155
155
@@ -163,7 +163,7 @@ and the Scala compiler will generate the following error message:
163
163
164
164
Because the constructor parameter must be a `val`, it cannot be a by-name parameter:
165
165
166
-
NoByName.scala:1: error: `val' parameters may not be call-by-name
166
+
NoByName.scala:1: error: `val` parameters may not be call-by-name
167
167
class NoByName(val x: => Int) extends AnyVal
168
168
^
169
169
@@ -178,25 +178,29 @@ Multiple constructors are not allowed:
178
178
def this(y: Double) = this(y.toInt)
179
179
^
180
180
181
-
A value class cannot have lazy vals or vals as members and cannot have nested classes, traits, or objects:
181
+
A value class cannot have lazy vals, vars, or vals as members and cannot have nested classes, traits, or objects:
182
182
183
183
class NoLazyMember(val evaluate: () => Double) extends AnyVal {
184
184
val member: Int = 3
185
+
var y: Int = 4
185
186
lazy val x: Double = evaluate()
186
187
object NestedObject
187
188
class NestedClass
188
189
}
189
190
190
-
Invalid.scala:2: error: this statement is not allowed in value class: private[this] val member: Int = 3
191
+
Invalid.scala:2: error: this statement is not allowed in value class: val member: Int = 3
191
192
val member: Int = 3
192
193
^
193
-
Invalid.scala:3: error: this statement is not allowed in value class: lazy private[this] var x: Double = NoLazyMember.this.evaluate.apply()
194
+
Invalid.scala:3: error: this statement is not allowed in value class: var y: Int = 4
195
+
var y: Int = 4
196
+
^
197
+
Invalid.scala:4: error: this statement is not allowed in value class: lazy val x: Double = NoLazyMember.this.evaluate.apply()
194
198
lazy val x: Double = evaluate()
195
199
^
196
-
Invalid.scala:4: error: value class may not have nested module definitions
200
+
Invalid.scala:5: error: value class may not have nested module definitions
197
201
object NestedObject
198
202
^
199
-
Invalid.scala:5: error: value class may not have nested class definitions
203
+
Invalid.scala:6: error: value class may not have nested class definitions
200
204
class NestedClass
201
205
^
202
206
@@ -208,6 +212,10 @@ Note that local classes, traits, and objects are not allowed either, as in the f
208
212
...
209
213
}
210
214
}
215
+
216
+
Local.scala:3: error: implementation restriction: nested class is not allowed in value class
217
+
class Local
218
+
^
211
219
212
220
A current implementation restriction is that value classes cannot be nested:
0 commit comments