Scala 2.10 introduced value classes. They are very usefull for writing typesafe code. Moreover there are some limitations, some of them will be detected by compiler, and some will require allocation in runtime.
I want to create value classes using case class
syntax, to allow creating-without-new-syntax and human-friendly toString
. No pattern matching, cause it requires allocation.
So the question is: will using case class
syntax require value class allocation?
A Scala Case Class is like a regular class, except it is good for modeling immutable data. It also serves useful in pattern matching, such a class has a default apply() method which handles object construction. A scala case class also has all vals, which means they are immutable.
Value classes are a new mechanism which help to avoid allocating run time objects. AnyVal define value classes. Value classes are predefined, they coincide to the primitive kind of Java-like languages. There are nine predefined value types : Double, Float, Long, Int, Short, Byte, Char, Unit, and Boolean.
A class can extend another class, whereas a case class can not extend another case class (because it would not be possible to correctly implement their equality).
A case object, on the other hand, does not take args in the constructor, so there can only be one instance of it (a singleton like a regular scale object is). A case object is a singleton case class.
You can have a case class that is a value class. As you can see from the example below, there is no object creation. Except of course the inevitable boxing if you would upcast to Any.
Here is a little piece of scala code
class ValueClass(val value:Int) extends AnyVal case class ValueCaseClass(value:Int) extends AnyVal class ValueClassTest { var x: ValueClass = new ValueClass(1) var y: ValueCaseClass = ValueCaseClass(2) def m1(x:ValueClass) = x.value def m2(x:ValueCaseClass) = x.value }
And the bytecode, which does not contain the slightest trace of the two value classes.
Compiled from "ValueClassTest.scala" public class ValueClassTest { public int x(); Code: 0: aload_0 1: getfield #14 // Field x:I 4: ireturn public void x_$eq(int); Code: 0: aload_0 1: iload_1 2: putfield #14 // Field x:I 5: return public int y(); Code: 0: aload_0 1: getfield #21 // Field y:I 4: ireturn public void y_$eq(int); Code: 0: aload_0 1: iload_1 2: putfield #21 // Field y:I 5: return public int m1(int); Code: 0: iload_1 1: ireturn public int m2(int); Code: 0: iload_1 1: ireturn public rklaehn.ValueClassTest(); Code: 0: aload_0 1: invokespecial #29 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_1 6: putfield #14 // Field x:I 9: aload_0 10: iconst_2 11: putfield #21 // Field y:I 14: return }
To extends this question, Wojciech Langiewicz proposes a nice example of Value class used as case class.
Instead of:
case class Player(id: Int, gameCash: Int, gameCoins: Int, energy: Int)
Wojciech defines:
case class Player(id: PlayerId, gameCash: GameCash, gameCoins: GameCoins, energy: Energy)
with the case classes (without allocation of additional objects on the heap):
case class PlayerId(id: Int) extends AnyVal case class GameCash(value: Int) extends AnyVal case class GameCoins(value: Int) extends AnyVal case class Energy(value: Int) extends AnyVal
When creating case classes that wrap exactly one parameter you should add
extends AnyVal
to allow Scala compiler to run more optimizations – basically type checking will be done only during compilation phase, but during runtime only objects of the underlying type will be created which leads to less memory overhead.Adding custom types in the specific points in our code not only improved readability but also allowed us to make less errors – offload some of the checking that otherwise would have to be done in tests (or not done at all) to the compiler. You can also immediately see errors in your IDE or editor.
Because now each component in the
Player
class is itself a separate type, it’s also very easy to add new operators that otherwise probably would have to be added implicitly which would pollute larger scope.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With