Normal
Normal

Reputation: 1367

Does scala case class named parameters have some performance cost?

I've found pretty convenient to use that in my project:

case class Thing(a: Option[String], b: Option[String], c: Option[String])
...
val a = Thing(a = Some("A"))
val b = Thing(b = Some("B"))
val c = Thing(b = Some("B"), c = Some("C"))

it actually reduce a lot of ugly None definitions and looks much readable, but now I'm wondering is there any difference from performance/implementation point of view between this and that?:

val a = Thing(Some("A"), None, None)
val b = Thing(None, Some("B"), None)
val c = Thing(None, Some("B"), Some("C"))

Thanks

Upvotes: 2

Views: 252

Answers (1)

Silvio Mayolo
Silvio Mayolo

Reputation: 70267

Semantically, there's no difference, since None is a singleton object. However, performance-wise, we can see what sort of code is being generated under the hood.

case class Thing(
  a: Option[String] = None,
  b: Option[String] = None,
  c: Option[String] = None
)

object Thing {
  def foo() = {
    val a1 = Thing(a = Some("A"))
    val b1 = Thing(b = Some("B"))
    val c1 = Thing(b = Some("B"), c = Some("C"))

    val a2 = Thing(Some("A"), None, None)
    val b2 = Thing(None, Some("B"), None)
    val c2 = Thing(None, Some("B"), Some("C"))
  }
}

This is an example of the sort of thing you're asking about, I believe. We can compile this with scalac Thing.java -Xprint:jvm to see what the Scala compiler is left with after it strips all the syntax sugar out.

val a1: Thing = new Thing(new Some("A"), Thing.apply$default$2(), Thing.apply$default$3());
val b1: Thing = {
  <artifact> val x$1: Some = new Some("B");
  <artifact> val x$2: Option = Thing.apply$default$1();
  <artifact> val x$3: Option = Thing.apply$default$3();
  new Thing(x$2, x$1, x$3)
};
val c1: Thing = {
  <artifact> val x$4: Some = new Some("B");
  <artifact> val x$5: Some = new Some("C");
  <artifact> val x$6: Option = Thing.apply$default$1();
  new Thing(x$6, x$4, x$5)
};
val a2: Thing = new Thing(new Some("A"), scala.None, scala.None);
val b2: Thing = new Thing(scala.None, new Some("B"), scala.None);
val c2: Thing = new Thing(scala.None, new Some("B"), new Some("C"));

So using the named syntax can introduce some intermediate variables. But the function call is essentially the same modulo a few bytes of stack space. More than likely, the JIT will compile these down to similarly performing snippets of code, so I'd say you have little to worry about.

Upvotes: 1

Related Questions