Scala: Get value of child from parent? - scala

Trying to get values of all fields of child from parent class like this:
for (field <- this.getClass.getDeclaredFields) {
Logger.debug(field.getName)
field.get(this)
}
and got error
Exception: Class models.Model$$anonfun$4 can not access a member of
class models.Good with modifiers "private"
at line
field.get(this)
In Good class I don't have private fields:
class Good(id: Option[String]) extends Model[realGood](id){
lazy val title: String = this.load[String](realObject.get.title)
lazy val cost: Double = this.load[Double](realObject.get.cost)
}
What's wrong with this code?

As hinted in the comments, Scala's conversion to java bytecode isn't always straightforward (though it's usually pretty predictable, once you get the hang of it). In particular, public fields in Scala compile to a private field with a public getter in java bytecode:
fukaeri:~ dlwh$ cat zzz.scala
class Good(id: Option[String]) {
lazy val title: String = ???
lazy val cost: Double = ???
}
fukaeri:~ dlwh$ scalac zzz.scala
fukaeri:~ dlwh$ javap -private Good
Compiled from "zzz.scala"
public class Good {
private java.lang.String title;
private double cost;
private volatile byte bitmap$0;
private java.lang.String title$lzycompute();
private double cost$lzycompute();
public java.lang.String title();
public double cost();
public Good(scala.Option<java.lang.String>);
}
You can see that Good has private fields for each of your declared public fields, in addition to public getters. Because the fields are lazy val, they also have computation methods for initialization, and there's a bitmap$0 field to ensure that the lazy vals are initialized only once.
In your loop, you can use field.setAccessible(true) to fix your exception.

Related

Can a Scala compiler plugin transform the autogenerated accessor methods of scala case classes?

After the parser phase of the Scalac process, the following case class
case class ExampleCaseClass(var s:String, var i:Int) extends ContextuallyMutable
takes the intermediate form:
Clazz(case class ExampleCaseClass extends ContextuallyMutable with scala.Product with scala.Serializable {
<caseaccessor> <paramaccessor> var s: String = _;
<caseaccessor> <paramaccessor> var i: Int = _;
def <init>(s: String, i: Int) = {
super.<init>();
()
}
})
However, a run time reflection call:
ExampleCaseClass("Can a Scala compiler plugin transform the autogenerated accessor methods of scala case classes?", 42).getClass.getMethods.foreach(println(_))
reveals many more public methods:
public boolean ExampleCaseClass.equals(java.lang.Object)
public java.lang.String ExampleCaseClass.toString()
public int ExampleCaseClass.hashCode()
public static ExampleCaseClass ExampleCaseClass.apply(java.lang.String,int)
public int ExampleCaseClass.i()
public java.lang.String ExampleCaseClass.s()
public ExampleCaseClass ExampleCaseClass.copy(java.lang.String,int)
public void ExampleCaseClass.i_$eq(int)
public scala.collection.Iterator ExampleCaseClass.productElementNames()
public java.lang.String ExampleCaseClass.productElementName(int)
public void ExampleCaseClass.s_$eq(java.lang.String)
public int ExampleCaseClass.copy$default$2()
public boolean ExampleCaseClass.canEqual(java.lang.Object)
public java.lang.String ExampleCaseClass.productPrefix()
public int ExampleCaseClass.productArity()
public java.lang.Object ExampleCaseClass.productElement(int)
public scala.collection.Iterator ExampleCaseClass.productIterator()
public java.lang.String ExampleCaseClass.copy$default$1()
public static scala.Function1 ExampleCaseClass.tupled()
public static scala.Option ExampleCaseClass.unapply(ExampleCaseClass)
public static scala.Function1 ExampleCaseClass.curried()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
Clearly some subsequent compiler phase creates the property accessor methods:
public int ExampleCaseClass.i()
public java.lang.String ExampleCaseClass.s()
public void ExampleCaseClass.i_$eq(int)
public void ExampleCaseClass.s_$eq(java.lang.String)
Which compilation phase generates these accessor methods and what manner of compiler plugin (or other means) might prevent or transform them?
The enquirer has already run numerous experiments removing or reshaping the:
<caseaccessor> <paramaccessor> var s: String = _;
<caseaccessor> <paramaccessor> var i: Int = _;
portions of the case class, and also with injecting the desired accessor methods in advance but no combination has met the desired outcome. They either fail to compile because of naming conflicts that arise in subsequent compilation phases, or they alter the parameter names in constructor, apply, and accessor methods.
Can a scala compiler plugin transform synthetic accessors at all? Does the Java Compiler introduce these methods? If so, should the enquirer look to Javac plugins and what analogues might serve the Scala.js and Scala native compilation targets?
Thank you for any consideration.
case class expansion happens in more than one place, see another question.
Instead of writing a new plugin just to disallow using var it would be much better to add a new rule to Wartremover or ScalaFix. As a matter of the fact, these rules already exist:
disallow var with Wartremover - combine it with fatal warnings to fail compilation on var
disallow var with ScalaFix
If you want to add more elaborate rule... it would still be easier just to write your own Wartremover/ScalaFix rule (the latter might be preferred as it is already supported in Scala 3).
And if you really need a custom compiler plugin to mess with code generated by compiler... take a look at better-toString plugin. It adds its own phase after "parser" phase. But I wouldn't hope for removing the autogenerated implementations. At best you can override them manually where specs allows you to.
The enquirer found a Scala 3 solution with persistence and help from examples:
better-tostring a plugin that demonstrates conditional method insertion by Polyvariant.
Compiler Plugin Development in Scala 3 Example and Tutorial by Scala Center dev: Fengyun Liu. The video provided insights into compiler phases and the example shed light on method body generation syntax. In particular, available documentation doesn't readily clarify how to call println from a method body generated as a Tree by a compiler plugin, but Liu's example plugin demonstrated requireModule and requiredMethod.
Scala 3 Compiler Plugin Documentation offers a very nice template for how to start writing a plugin. The final solution looked very similar.
As of 26 Nov 2021, no solution exists for Scala 2.13, but maybe that just means it is time to upgrade.
final class BlockMutatorPlugin extends StandardPlugin {
override val name: String = "BlockMutatorPlugin"
override val description: String = "Scala Compiler Plugin for blocking ContextuallyMutable setter methods."
override def init(options: List[String]): List[PluginPhase] = List(new BlockContextuallyMutableSetters)
}
class BlockContextuallyMutableSetters extends PluginPhase {
val phaseName = "blockGetter"
/* Running this plugin after phases before ElimErasedValueType
resulted in the replacement of the generated setter methods by the synthetic
default versions. By the time that this ElimErasedValueType phase ends, the
defaults already existed, so this plugin could augment them safely. */
override val runsAfter = Set(ElimErasedValueType.name)
private var printBlocked: Tree = _
override def prepareForTemplate(tree: tpd.Template)(using ctx: Context): Context = {
val cnsl = requiredModule("scala.Predef")
val prntln: PreName = "println".toTermName
val say = cnsl.requiredMethod(prntln, List[Types.Type](ctx.definitions.ObjectType))
printBlocked = ref(say).appliedTo(Literal(Constant("Blocked!")))
ctx
}
override def transformTemplate(tree: Template)(using ctx: Context): Tree = {
if (tree.parents.filter(_.symbol.name.toString.equals("ContextuallyMutable")).nonEmpty) {
cpy.Template(tree)(
body = tree.body.collect {
case dd: DefDef if dd.name.isSetterName => DefDef(
dd.symbol.asInstanceOf[Symbols.TermSymbol],
printBlocked
)
case x => x
}
).asInstanceOf[Tree]
} else tree
}
}
The most important part of this effort involved discovering which compiler phase this plugin should follow. Similar efforts in Scala 2.13.6 have failed so far; the only remaining impediment to the Scala 2 solution sought by this original Stack Overflow question. As such, the enquirer will not mark his own answer as the accepted solution unless future edits avail Scala 2. Until that time, your response may claim that designation.
For any inclined to try compile this example, the code above requires the following import statements:
import dotty.tools.dotc.ast.tpd
import tpd.*
import dotty.tools.dotc.core.*
import Names.PreName
import Symbols.{ClassSymbol, requiredMethod, requiredModule}
import Decorators.*
import NameOps.*
import Contexts.Context
import Constants.Constant
import dotty.tools.dotc.plugins.*
import dotty.tools.dotc.transform.ElimErasedValueType

Understanding Case class and Traits in Scala

I have a simple trait as defined below:
trait MyTrait {
def myStringVal: String
}
My case class which implements this trait is as below:
case class MyCaseClass(myStringVal: String) extends MyTrait {
...
...
}
Coming from a Java world, I find it a bit difficult to fathom the fact that MyCaseClass actually implements this just by defining a parameter to MyCaseClass. I understand that thy byte code would actually write the getter and setter. But how is this possible without any var or val?
My understanding is that if there is no var or val, then there is no getter or setter method generated. In that case how is the above case class MyCaseClass implementing myStringVal method?
Sometime too much of this Scala magic is difficult to understand especially with legacy code.
You might want to check out this blog article covering what case classes exactly are and why they are so useful.
In your example, the trait MyTrait has no use, except being able to function like a java interface. Note, that the default visibility in scala is public. By default case class parameters are immutable so in your example val is automatically inferred by the compiler for the myStringVal argument.
What magic do case classes do?!
Convert all constructor parameters to public readonly (val) by default fields
Generate the toString(), equals() and hashcode() methods using all constructor params for each method
Generate companion object with the same name containing an appropriate apply() and unapply() method, which are basically just a convenience constructor allowing to instantiate without using the new keyword and an extractor which by default generates an option-wrapped tuple of the case class parameters.
EDIT: Sample compiler output for (case) classes (copied from scalatutorial.de)
A simple scala class definition like
class A1(v1: Int, v2: Double)
gets compiled to the java code
public class A1 extends java.lang.Object implements scala.ScalaObject {
public A1(int, double);
}
the analogous case class
case class A2(v1: Int, v2: Double)
gets compiled to the following java classes
public class A2 extends java.lang.Object implements
scala.ScalaObject,scala.Product,java.io.Serializable {
public static final scala.Function1 tupled();
public static final scala.Function1 curry();
public static final scala.Function1 curried();
public scala.collection.Iterator productIterator();
public scala.collection.Iterator productElements();
public double copy$default$2();
public int copy$default$1();
public int v1();
public double v2();
public A2 copy(int, double);
public int hashCode();
public java.lang.String toString();
public boolean equals(java.lang.Object);
public java.lang.String productPrefix();
public int productArity();
public java.lang.Object productElement(int);
public boolean canEqual(java.lang.Object);
public A2(int, double);
}
public final class A2$ extends scala.runtime.AbstractFunction2
implements scala.ScalaObject {
public static final A2$ MODULE$;
public static {};
public scala.Option unapply(A2);
public A2 apply(int, double);
public java.lang.Object apply(java.lang.Object, java.lang.Object);
}
Scala case classes have a plenty of boilerplate implemented for you, and having all the constructor parameters automatically exposed as vals is one of these things.
If you try avoiding vals in a regular class, like that:
trait MyTrait {
def myVal: String
}
class MyClass(myVal: String) extends MyTrait
Compiler will show you the error message, that MyClass has to be abstract, as it does't override myVal method, but adding val or var to the class constructor parameter will solve the issue.
Case classes are different -- some default methods are generated for them. This includes val getters for the parameters. Think of case classes as POJOs -- this is a useful bit of syntactic sugar, since they don't need private members.
Some other useful methods are generated too, for example copy, toString, apply and unapply.

Object-private variables implementation

I'm trying to understand implementation of object-private variables in Scala. Scala compiles this class
class Counter{
private[this] var age = 0
}
into the following java byte code:
public class Counter implements scala.ScalaObject {
private int age;
public Counter();
}
But still, because JVM doesn't support object-private fields, we have good-old private field, which can be accessed from other instances of the class. So for me the difference between previous class and the following in terms of hiding private field is not clear.
class Counter2{
private var age = 0
}
public class Counter2 implements scala.ScalaObject {
private int age;
private int age();
private void age_$eq(int);
public Counter2();
}
The JVM is irrelevant. The semantics of Scala are implemented by the Scala compiler, not the JVM. After all, the JVM isn't even the only platform Scala runs on, there are production-ready implementations of Scala on the CLI, and experimental ones on ECMAScript as well as a native one.

In Scala, is it possible to have a case class containing methods with identical names to fields?

I think I'd like to be able to do something like the following (clearly garbage) code illustrates:
// Clearly nonsensical
case class Example(a: String) {
def a: Array[Byte] = a.getBytes
}
The gist of it is that I want to write an accessor method for a case class that is named identically to one of its constructor arguments.
I'm using a JSON serialization library called Jerkson that, according to my understanding, will behave in the way I want it to if I define a class in this manner. I'm basing that assumption on this code. Currently, I'm stumped.
If this isn't possible, could anyone offer some insight on what the Jerkson library code is attempting to do?
Scala automatically creates a method with the same name as any val declared in a class (including the fields of case classes) to support a concept called referential transparency. This is also why you can override a def with a val. If you're still skeptical, you can test it yourself like this:
First, create a Scala file with a single case class.
// MyCase.scala
case class MyCase(myField1: Int, myField2: String)
Now, compile the file with scalac. This should result in two classes. For the example above I get MyCase.class (representing the actual case class type) and MyCase$.class (representing the auto-generated companion object for the case class).
$ scalac MyCase.scala
$ ls
MyCase$.class MyCase.class MyCase.scala
Now you can examine the resulting .class file corresponding to the case class you declared using javap. (javap standard tool for examining Java bytecode—it's distributed along with javac in the JDK.)
$ javap -private MyCase
Compiled from "MyCase.scala"
public class MyCase extends java.lang.Object implements scala.Product,scala.Serializable{
private final int myField1;
private final java.lang.String myField2;
public static final scala.Function1 tupled();
public static final scala.Function1 curry();
public static final scala.Function1 curried();
public scala.collection.Iterator productIterator();
public scala.collection.Iterator productElements();
public int myField1();
public java.lang.String myField2();
public MyCase copy(int, java.lang.String);
public java.lang.String copy$default$2();
public int copy$default$1();
public int hashCode();
public java.lang.String toString();
public boolean equals(java.lang.Object);
public java.lang.String productPrefix();
public int productArity();
public java.lang.Object productElement(int);
public boolean canEqual(java.lang.Object);
private final boolean gd1$1(int, java.lang.String);
public MyCase(int, java.lang.String);
}
Notice how the resulting class has both a private final int myField1 and a public int myField1() corresponding to the case class's myField1 field. The same for myField2.
On the JVM method return types are not part of the method signature. This means that if two methods have the same name and the same argument types then they're considered to be conflicting method declarations. This means you can't declare the def a: Array[Byte] in your example because val a: String already exists, also taking no arguments.
Update:
I just looked at the library code and according to the examples the case classes should just work. There is a note in the README saying that parsing case classes does not work in the REPL. Could that be your problem? If not, you should really post the error you're getting. Edit: Never mind, I see the error you're talking about in your link to your other post. If I think of a response to that problem I'll post it over there.
No, it's not possible. The reason is that constructor arguments of case classes are automatically public values, like if you declare them with val. To quote A Tour of Scala: Case Classes
The constructor parameters of case classes are treated as public values and can be accessed directly.
Therefore, for each constructor argument Scala creates a corresponding accessor method with the same name. You cannot create a method with the same name, it's already there.
This is actually what case classes are about. The idea is that they can be used for pattern matching, so the values retrieved from them should be the same as the values used to construct them.
(Is it a requirement that you use case classes? Using regular classes seems to solve the problem.)

Difference between case object and object

Is there any difference between case object and object in scala?
Here's one difference - case objects extend the Serializable trait, so they can be serialized. Regular objects cannot by default:
scala> object A
defined module A
scala> case object B
defined module B
scala> import java.io._
import java.io._
scala> val bos = new ByteArrayOutputStream
bos: java.io.ByteArrayOutputStream =
scala> val oos = new ObjectOutputStream(bos)
oos: java.io.ObjectOutputStream = java.io.ObjectOutputStream#e7da60
scala> oos.writeObject(B)
scala> oos.writeObject(A)
java.io.NotSerializableException: A$
Case classes differ from regular classes in that they get:
pattern matching support
default implementations of equals and hashCode
default implementations of serialization
a prettier default implementation of toString, and
the small amount of functionality that they get from automatically inheriting from scala.Product.
Pattern matching, equals and hashCode don't matter much for singletons (unless you do something really degenerate), so you're pretty much just getting serialization, a nice toString, and some methods you probably won't ever use.
scala> object foo
defined object foo
scala> case object foocase
defined object foocase
Serialization difference:
scala> foo.asInstanceOf[Serializable]
java.lang.ClassCastException: foo$ cannot be cast to scala.Serializable
... 43 elided
scala> foocase.asInstanceOf[Serializable]
res1: Serializable = foocase
toString difference:
scala> foo
res2: foo.type = foo$#7bf0bac8
scala> foocase
res3: foocase.type = foocase
A huge necro, but it is the highest result for this question in Google outside official tutorial which, as always, is pretty vague about the details. Here are some bare bones objects:
object StandardObject
object SerializableObject extends Serializable
case object CaseObject
Now, lets use the very useful feature of IntelliJ 'decompile Scala to Java' on compiled .class files:
//decompiled from StandardObject$.class
public final class StandardObject$ {
public static final StandardObject$ MODULE$ = new StandardObject$();
private StandardObject$() {
}
}
//decompiled from StandardObject.class
import scala.reflect.ScalaSignature;
#ScalaSignature(<byte array string elided>)
public final class StandardObject {
}
As you can see, a pretty straightforward singleton pattern, except for reasons outside the scope of this question, two classes are generated: the static StandardObject (which would contain static forwarder methods should the object define any) and the actual singleton instance StandardObject$, where all methods defined in the code end up as instance methods. Things get more intresting when you implement Serializable:
//decompiled from SerializableObject.class
import scala.reflect.ScalaSignature;
#ScalaSignature(<byte array string elided>)
public final class SerializableObject {
}
//decompiled from SerializableObject$.class
import java.io.Serializable;
import scala.runtime.ModuleSerializationProxy;
public final class SerializableObject$ implements Serializable {
public static final SerializableObject$ MODULE$ = new SerializableObject$();
private Object writeReplace() {
return new ModuleSerializationProxy(SerializableObject$.class);
}
private SerializableObject$() {
}
}
The compiler doesn't limit itself to simply making the 'instance' (non-static) class Serializable, it adds a writeReplace method. writeReplace is an alternative to writeObject/readObject; what it does, it serializes a different object whenether the Serializable class having this method is being serialized. On deserializention then, that proxy object's readResolve method is invoked once it is deserialized. Here, a ModuleSerializableProxy instance is serialized with a field carrying the Class[SerializableObject], so it knows what object needs to be resolved. The readResolve method of that class simply returns SerializableObject - as it is a singleton with a parameterless constructor, scala object is always structurally equal to itself between diffrent VM instances and different runs and, in this way, the property that only a single instance of that class is created per one VM instance is preserved. A thing of note is that there is a security hole here: no readObject method is added to SerializableObject$, meaning an attacker can maliciously prepare a binary file which matches standard Java serialization format for SerializableObject$ and a separate instance of the 'singleton' will be created.
Now, lets move to the case object:
//decompiled from CaseObject.class
import scala.collection.Iterator;
import scala.reflect.ScalaSignature;
#ScalaSignature(<byte array string elided>)
public final class CaseObject {
public static String toString() {
return CaseObject$.MODULE$.toString();
}
public static int hashCode() {
return CaseObject$.MODULE$.hashCode();
}
public static boolean canEqual(final Object x$1) {
return CaseObject$.MODULE$.canEqual(var0);
}
public static Iterator productIterator() {
return CaseObject$.MODULE$.productIterator();
}
public static Object productElement(final int x$1) {
return CaseObject$.MODULE$.productElement(var0);
}
public static int productArity() {
return CaseObject$.MODULE$.productArity();
}
public static String productPrefix() {
return CaseObject$.MODULE$.productPrefix();
}
public static Iterator productElementNames() {
return CaseObject$.MODULE$.productElementNames();
}
public static String productElementName(final int n) {
return CaseObject$.MODULE$.productElementName(var0);
}
}
//decompiled from CaseObject$.class
import java.io.Serializable;
import scala.Product;
import scala.collection.Iterator;
import scala.runtime.ModuleSerializationProxy;
import scala.runtime.Statics;
import scala.runtime.ScalaRunTime.;
public final class CaseObject$ implements Product, Serializable {
public static final CaseObject$ MODULE$ = new CaseObject$();
static {
Product.$init$(MODULE$);
}
public String productElementName(final int n) {
return Product.productElementName$(this, n);
}
public Iterator productElementNames() {
return Product.productElementNames$(this);
}
public String productPrefix() {
return "CaseObject";
}
public int productArity() {
return 0;
}
public Object productElement(final int x$1) {
Object var2 = Statics.ioobe(x$1);
return var2;
}
public Iterator productIterator() {
return .MODULE$.typedProductIterator(this);
}
public boolean canEqual(final Object x$1) {
return x$1 instanceof CaseObject$;
}
public int hashCode() {
return 847823535;
}
public String toString() {
return "CaseObject";
}
private Object writeReplace() {
return new ModuleSerializationProxy(CaseObject$.class);
}
private CaseObject$() {
}
}
A lot more is going on, as CaseObject$ now implements also Product0, with its iterator and accessor methods. I am unaware of a use case for this feature, it is probably done for consistency with case class which is always a product of its fields. The main practical difference here is that we get canEqual, hashCode and toString methods for free. canEqual is relevant only if you decide to compare it with a Product0 instance which is not a singleton object, toString saves us from implementing a single simple method, which is useful when case objects are used as enumeration constants without any behaviour implemented. Finally, as one might suspect, hashCode returns a constant, so it is the same for all VM instances. This matters if one serializes some flawed hash map implementation, but both standard java and scala hash maps wisely rehash all contents on deserialization, so it shouldn't matter. Note that equals is not overriden, so it is still reference equality, and that the security hole is still there. A huge caveat here: if a case object inherit equals/toString from some supertype other than Object, the corresponding methods are not generated, and the inherited definitions are used instead.
TL;DR: the only difference that matters in practice is the toString returning the unqualified name of the object.
I must make a disclamer here, though: I cannot guarantee that the compiler doesn't treat case objects specially in addition to what is actually in the bytecode. It certainly does so when patterm matching case classes, aside from them implementing unapply.
It's similar with case class and class ,we just use case object instead of case class when there isn't any fields representing additional state information.
case objects implicitly come with implementations of methods toString, equals, and hashCode, but simple objects don't.
case objects can be serialized while simple objects cannot, which makes case objects very useful as messages with Akka-Remote.
Adding the case keyword before object keyword makes the object serializable.
We know objects and "case class" before. But "case object" is a mix of both i.e it is a singleton similar to an object and with a lot of boilerplate as in a case class. The only difference is that the boilerplate is done for an object instead of a class.
case objects won't come with the below ones:
Apply, Un-apply methods.
here are no copy methods since this is a singleton.
No method for structural equality comparison.
No constructor as well.