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 classexpansion happens in more than one place, see another question.Instead of writing a new plugin just to disallow using
varit would be much better to add a new rule to Wartremover or ScalaFix. As a matter of the fact, these rules already exist:varwith Wartremover - combine it with fatal warnings to fail compilation onvarvarwith ScalaFixIf 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.