What methods are generated for Scala case classes? - scala

What methods are generated for Scala case classes?
I know that some methods are generated specifically for case classes:
equals
canEqual
What are the others?
Also, I see that I can call productArity() on any case class. How does this work? In other words, why the following code is valid?
case class CaseClass()
object CaseClass {
val cc = new CaseClass()
cc.productArity
}

A good way what methods are generated for a specific class in Scala is to use the javap command.
Find the .class file that was compiled by scalac and then run the javap -private command on it from your respective command line tool. This will show you the constructors, fields, and all methods for a class.
You can do this for your case class to see what kinds of things are automagically supplied by Scala.
Case classes mixin the Product trait which provides the productArity method. For case classes the productArity method will return the count of the parameter list supplied in the class definition.

Given Test.scala -
case class Test()
You can run scalac Test.scala -print to see exactly what's generated
[[syntax trees at end of cleanup]] // Test.scala
package com {
case class Test extends Object with Product with Serializable {
<synthetic> def copy(): com.Test = new com.Test();
override <synthetic> def productPrefix(): String = "Test";
<synthetic> def productArity(): Int = 0;
<synthetic> def productElement(x$1: Int): Object = {
case <synthetic> val x1: Int = x$1;
case4(){
matchEnd3(throw new IndexOutOfBoundsException(scala.Int.box(x$1).toString()))
};
matchEnd3(x: Object){
x
}
};
override <synthetic> def productIterator(): Iterator = runtime.this.ScalaRunTime.typedProductIterator(Test.this);
<synthetic> def canEqual(x$1: Object): Boolean = x$1.$isInstanceOf[com.Test]();
override <synthetic> def hashCode(): Int = ScalaRunTime.this._hashCode(Test.this);
override <synthetic> def toString(): String = ScalaRunTime.this._toString(Test.this);
override <synthetic> def equals(x$1: Object): Boolean = {
case <synthetic> val x1: Object = x$1;
case5(){
if (x1.$isInstanceOf[com.Test]())
matchEnd4(true)
else
case6()
};
case6(){
matchEnd4(false)
};
matchEnd4(x: Boolean){
x
}
}.&&(x$1.$asInstanceOf[com.Test]().canEqual(Test.this));
def <init>(): com.Test = {
Test.super.<init>();
scala.Product$class./*Product$class*/$init$(Test.this);
()
}
};
<synthetic> object Test extends scala.runtime.AbstractFunction0 with Serializable {
final override <synthetic> def toString(): String = "Test";
case <synthetic> def apply(): com.Test = new com.Test();
case <synthetic> def unapply(x$0: com.Test): Boolean = if (x$0.==(null))
false
else
true;
<synthetic> private def readResolve(): Object = com.this.Test;
case <synthetic> <bridge> <artifact> def apply(): Object = Test.this.apply();
def <init>(): com.Test.type = {
Test.super.<init>();
()
}
}
}

It's true that a case classe automatically define equals and canEqual methods but it's also define getter methods for the constructor arguments. There's also a toString method that you can call.
A case class is also an instance of Product and thus inherit these methods. This is why you call productArity.

Related

Scala: Creating a trait that forces classes to re-implement certain methods

I am trying to implement a trait that forces each class that extends it (and is not abstract) to implement certain methods (even if they already exist in super-classes). Concretely it should look like this:
trait Debugable {
override def hashCode(): Int = ???
override def equals(obj: Any): Boolean = ???
override def toString: String = ???
}
That is the trait and this the implementation:
class TestClass {
}
object TestClass{
def main(args: Array[String]): Unit = {
val t = new TestClass
println(t)
}
}
The code above should ideally not compile (since a debugable class does not implement the required methods). In reality this does not only compile, but also throws no run-time exception (it just takes the default implementations of the object class).
Until now nothing managed to generate the expected behaviour. I think macros could help, but I am unsure if macros can express something like:
foreach class
if class.traits.contains(debugable)
return class.methods.contains(toString)
I know that I could let some external script do the check and have it bundled with the gradle compile task, but I am hoping for a solution which can be implemented as part of the project itself (since that would make it independent of the build pipeline used and since it should be simpler and easier to maintain/extend than writing a script crawling the entire source code)
This is close to it (and certainly an improvement over what I have),
but it does not do exactly what I wanted. If I have a "chain" of
classes, then it is enough for the top of the chain to implement the
methods.
Typeclass approach can help with that, for example,
trait Debuggable[T] {
def hashCode(v: T): Int
def equals(v: T, b: Any): Boolean
def toString(v: T): String
}
class Foo
class Bar
class Qux extends Foo
object Debuggable {
implicit val fooDebuggable: Debuggable[Foo] = new Debuggable[Foo] {
def hashCode(v: Foo) = 42
def equals(v: Foo, b: Any) = true
def toString(v: Foo) = "woohoo"
}
implicit val barDebuggable: Debuggable[Bar] = new Debuggable[Bar] {
def hashCode(v: Bar) = 24
def equals(v: Bar, b: Any) = false
def toString(v: Bar) = "boohoo"
}
}
import Debuggable._
def debug[T](v: T)(implicit ev: Debuggable[T]) = ???
debug(new Foo) // OK
debug(new Bar) // OK
debug(new Qux) // Error despite Qux <:< Foo
In my opinion you should just make it abstract.
// Start writing your ScalaFiddle code here
trait Debugable {
def debugHashCode:Int
def debugEquals(obj: Any): Boolean
def debugToString: String
override def hashCode(): Int = debugHashCode
override def equals(obj: Any): Boolean = debugEquals(obj)
override def toString: String = debugToString
}
//this will not compile
class TestClass extends Debugable { }
//this is OK but you need to implement 3 methods later :)
abstract class TestClass2 extends Debugable {}
https://scalafiddle.io/sf/bym3KFM/0
macros should be last thing you try.
Based upon this I wrote the following, which satisfies my need and does override the default implementations:
trait Debuggable_Helper[T]{
def hashCode(v: T): Int
def equals(v: T, b: Any): Boolean
def toString(v: T): String
}
trait Debuggable[T] extends Debuggable_Helper [Debuggable [T]]{
override def hashCode(): Int = hashCode(this)
override def equals(b: Any): Boolean = equals(this, b)
override def toString(): String = toString(this)
}
class Foo extends Debuggable[Foo]{
def hashCode(v: Debuggable[Foo]) = 42
def equals(v: Debuggable[Foo], b: Any) = true
def toString(v: Debuggable[Foo]) = "woohoo"
}
class Qux extends Foo with Debuggable[Qux] //does not compile
object Test{
def main(args: Array[String]): Unit = {
println(new Foo) // OK - prints 'woohoo'
}
}

method or field in scala inheritance

I have following code snippet:
class Data(i: Int)
class Person(#transient val data: Data) extends java.io.Serializable
class Student(data: Data) extends Person(data)
I thought data is a field of Student class, but actually, it is a method of Student,
classOf[Student].getMethods.foreach(m => println(m.getName()),
The above code prints data
I would ask why data becomes method of Student, but not field,
thanks!
In Scala classes all public fields are actually private fields accessed via public methods.
This can be demonstrated using just your Data class, examining its status after phase 4 ("typer") of compilation.
%%> cat so.sc
class Data(i: Int)
%%> scalac -Xprint:4 so.sc
[[syntax trees at end of typer]] // so.sc
package <empty> {
class Data extends scala.AnyRef {
<paramaccessor> private[this] val i: Int = _;
def <init>(i: Int): Data = {
Data.super.<init>();
()
}
}
}
As you can see, val i is private[this] and if you run classOf[Data].getFields.isEmpty it will return true.
Now let's add a public field or two to it.
%%> cat so.sc
class Data(val i: Int) {
val x = 'X'
}
%%> scalac -Xprint:4 so.sc
[[syntax trees at end of typer]] // so.sc
package <empty> {
class Data extends scala.AnyRef {
<paramaccessor> private[this] val i: Int = _;
<stable> <accessor> <paramaccessor> def i: Int = Data.this.i;
def <init>(i: Int): Data = {
Data.super.<init>();
()
};
private[this] val x: Char = 'X';
<stable> <accessor> def x: Char = Data.this.x
}
}
We see that both vals, i and x, are private[this], and classOf[Data].getFields.isEmpty will still return true, but now there are also methods, def i and def x, that are public and return the expected values of Data.this.i and Data.this.x respectively.
Person has public getter method called data.
scala> :javap -public Person
Compiled from "<console>"
public class $line3.$read$$iw$$iw$Person implements java.io.Serializable {
public $line3.$read$$iw$$iw$Data data();
public $line3.$read$$iw$$iw$Person($line3.$read$$iw$$iw$Data);
}
Because Student is a child of Person it inherits this method.
Student has data too, but without var or val it's just a local variable, which is visible only in the body of Student, so it's not a member.
You can read more at Tour of Scala: Classes

Scala ambiguous case class generated and companion apply method

Given following code:
case class Foo(bar: String)
object Foo{
def apply(bar: String): Foo = Foo(bar)
}
If I was to call Foo("foo") I would end up with an infinite recursive call to def apply(bar: String). Of course, I could fix this problem by changing my apply implementation to def apply(bar: String): Foo = new Foo(bar). However, if I understand correctly, an apply method is generated for case classes with all their constructor parameters. My question then is two-fold:
1) If I myself wrote and then automatically generated a Foo.apply(bar: String): Foo, why do I not get a compilation error complaining about duplicate method definitions?
and
2) If generated method has a different signature, how can I call it?
why do I not get a compilation error complaining about duplicate method definitions?
Because your apply() code replaces the case class auto-generated code. They don't exist at the same time.
This can be demonstrated by compiling your code but dumping the intermediate state after the "typer" phase (phase 4) of the compilation.
%%> cat so.sc
case class Foo(bar: String)
object Foo{
def apply(bar: String): Foo = Foo(bar)
}
%%> scalac -Xprint:4 so.sc | less
The resulting output has only one object with only one apply() method.
object Foo extends scala.AnyRef with Serializable {
def <init>(): Foo.type = {
Foo.super.<init>();
()
};
def apply(bar: String): Foo = Foo.apply(bar);
case <synthetic> def unapply(x$0: Foo): Option[String] = if (x$0.==(null))
scala.None
else
Some.apply[String](x$0.bar);
<synthetic> private def readResolve(): Object = Foo
}
As you can see, the recursive apply() method resides amidst the auto-generated <synthetic> code.

Scala: companion objects from subclasses

I want to create a companion object that is subclass of a parameterized base class, and only fixes the base classes parameter -- that is, all methods are inherited from the base class.
One way to do this is with a trait:
class Foo(v: Int, printStream: PrintStream) {
def print: Unit = printStream.println(v);
}
trait FooFactory {
protected val printsTo: PrintStream
def apply(v: Int) = new Foo(v, printsTo)
def makeFoo(v: Int) = apply(v)
}
object Foo extends FooFactory {
protected val printsTo: PrintStream = System.out
}
val foo = Foo(3)
foo.print
val f2 = Foo.makeFoo(2)
f2.print
This way seems cleaner, but Intellij seems to think the base class methods are inaccessible outside the compilation unit (the .scala file that defines the companion):
class Bar(v: Int, printStream: PrintStream) {
def print: Unit = printStream.println(v);
}
class BarFactory(printsTo: PrintStream) {
def apply(v: Int) = new Bar(v, printsTo)
def makeBar(v: Int) = apply(v)
}
object Bar extends BarFactory(System.out) {}
val bar = Bar(3)
bar.print
val b2 = Bar.makeBar(2)
b2.print
Are these effectively equivalent (except for the name change Foo => Bar, of course)? Is one preferable?
The intent is to give the companion object a default PrintStream, while allowing users to create other factories if they need to:
val BarLoggerFactory = new BarFactory(someLogPrintStream)
val bar3 = BarLoggerFactory.makeBar(3);

How to recognize boxing/unboxing in a decompiled Scala code?

In the accepted best response to this question, there is a clear explanation why boxing happens.
However, if I decompile the code (using java decompiler) I cannot see use of scala.runtime.BoxesRunTime. Furthermore, if I profile the code (using JProfiler) I cannot see any instances of BoxesRunTime.
So, how do I really see a proof of boxing/unboxing taking place?
In this code:
class Foo[T] {
def bar(i: T) = i
}
object Main {
def main(args: Array[String]) {
val f = new Foo[Int]
f.bar(5)
}
}
The invocation of bar should first box the integer. Compiling with Scala 2.8.1 and using:
javap -c -l -private -verbose -classpath <dir> Main$
to see the bytecode produced for the main method of the Main class yields:
public void main(java.lang.String[]);
...
9: iconst_5
10: invokestatic #24; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
13: invokevirtual #28; //Method Foo.bar:(Ljava/lang/Object;)Ljava/lang/Object;
16: pop
17: return
...
You can see the call to BoxesRunTime before the call to bar.
BoxesRunTime is an object which contains boxing methods for primitive types, so there should be exactly one instance in total. The trick here is that this particular file in the library was written in Java, and the conversions are static methods. For this reason there aren't any instances of it at runtime, although using it in Scala code feels as if it were an object.
You should probably look for boxed primitives (e.g. java.lang.Integer) with JProfile, though I am uncertain how the JVM works and whether it may actually rewrite the code at runtime and optimize it to avoid boxing. To my knowledge, it shouldn't apply specialization (but I believe CLR does). A few microbenchmarks with and without the boxing situation are another way to figure out what happens at runtime.
EDIT:
The above is assuming that a type parameter wasn't annotated with the #specialized annotation. In this case, the boxing/unboxing can be avoided. Certain classes in the standard library are specialized. See this sid.
Given the following Test.scala program:
object Test {
def main(args:Array[String]) {
val list = List(1,5,15)
val res = list.map(e => e*2).filter(e => e>10)
}
}
If I compile with scalac -Xprint:jvm Test.scala, I get this snippet suggesting that specialization occurs (sorry for wide paste):
package <empty> {
final class Test extends java.lang.Object with ScalaObject {
def main(args: Array[java.lang.String]): Unit = {
val list: List = immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1, 5, 15}));
val res: List = list.map({
(new Test$$anonfun$1(): Function1)
}, immutable.this.List.canBuildFrom()).$asInstanceOf[scala.collection.TraversableLike]().filter({
(new Test$$anonfun$2(): Function1)
}).$asInstanceOf[List]();
()
};
def this(): object Test = {
Test.super.this();
()
}
};
#SerialVersionUID(0) #serializable final <synthetic> class Test$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp {
final def apply(e: Int): Int = Test$$anonfun$1.this.apply$mcII$sp(e);
<specialized> def apply$mcII$sp(v1: Int): Int = v1.*(2);
final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Int.box(Test$$anonfun$1.this.apply(scala.Int.unbox(v1)));
def this(): Test$$anonfun$1 = {
Test$$anonfun$1.super.this();
()
}
};
#SerialVersionUID(0) #serializable final <synthetic> class Test$$anonfun$2 extends scala.runtime.AbstractFunction1$mcZI$sp {
final def apply(e: Int): Boolean = Test$$anonfun$2.this.apply$mcZI$sp(e);
<specialized> def apply$mcZI$sp(v1: Int): Boolean = v1.>(10);
final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Boolean.box(Test$$anonfun$2.this.apply(scala.Int.unbox(v1)));
def this(): Test$$anonfun$2 = {
Test$$anonfun$2.super.this();
()
}
}
}
Could be why you don't see any evidence of boxing in bytecode...