A set of Scala macros for generating the methods defined on java.lang.Object
: equals
, hashCode
and toString
.
To add the dependency in sbt:
libraryDependencies += "io.methvin.standardmethods" %% "macros" % standardMethodsVersion % "provided"
where standardMethodsVersion
is the latest version:
For example, suppose you have a class with:
import io.methvin.standardmethods.macros._
class Person(val name: String, val age: Int, description: String) {
override def equals(other: Any) = equalsConstructorVals(this, other)
override def hashCode = hashCodeConstructorVals(this)
override def toString = toStringConstructorParams(this)
def canEqual(other: Any): Boolean = other.isInstanceOf[Person]
}
In this case, equals
and hashCode
will be generated from the val
s in the constructor of the class. toString
is generated by referencing the constructor params in scope. The generated code looks something like this:
import io.methvin.standardmethods.macros._
class Person(val name: String, val age: Int, description: String) {
override def equals(other: Any) = other match {
case other$macro$1: Person =>
other$macro$1.canEqual(this) &&
this.name == other$macro$1.name &&
this.age == other$macro$1.age
case _ => false
}
override def hashCode = scala.util.hashing.MurmurHash3.seqHash(
scala.collection.immutable.Seq(this.name, this.age))
override def toString = "Person" + Seq(name, age, description).mkString("(", ",", ")")
def canEqual(other: Any): Boolean = other.isInstanceOf[Person]
}
other canEqual this
is used if it is available. Otherwise this.getClass == that.getClass
is used to check if the type is compatible.
You can also use equalsAllVals
and hashCodeAllVals
to use all vals owned by the class rather than just those in the constructor. Note that this does not include vals defined in a superclass. Generally superclass vals can be handled by using equalsAllVals(this, that) && super.equals(that)
and hashCodeAllVals(this) ^ super.hashCode
. Contributions are welcome if someone wants to provide a more elegant solution.
Note: the macros are primarily meant to be used in a method of the class on which they are used, but equals
and hashCode
will work elsewhere as long as all the necessary methods are public. In other words, the macros for equals
and hashCode
themselves do not depend on the scope, since the instances used are passed directly, but the code they generate might not work due to privacy restrictions. The toStringConstructorParams
macro simply references the unprefixed constructor params, so it must be used within the class where it is needed.
This code is licensed under the Apache License, Version 2.0.
Please report an issue on this GitHub repository if you find anything that doesn't work as expected, or you have any feature requests. Your issue is much more likely to be fixed if you also submit a pull request to fix it yourself.