Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala. Can case class with one field be a value class?

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?

like image 612
Alex Povar Avatar asked Jul 15 '13 15:07

Alex Povar


People also ask

For which kind of data should you use a case class in Scala?

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.

What is a value class in Scala?

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.

What is difference between Case class and class in Scala?

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).

Is case a class singleton?

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.


2 Answers

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         } 
like image 64
Rüdiger Klaehn Avatar answered Sep 19 '22 12:09

Rüdiger Klaehn


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.

like image 24
VonC Avatar answered Sep 18 '22 12:09

VonC