简体   繁体   中英

In Scala is there a way to reference the Companion Object from within an instance of a Case Class?

In my specific case I have a (growing) library of case classes with a base trait ( TKModel )

Then I have an abstract class ( TKModelFactory[T <: TKModel] ) which is extended by all companion objects.

So my companion objects all inherently know the type ('T') of "answers" they need to provide as well as the type of objects they "normally" accept for commonly implemented methods. (If I get lazy and cut and paste chunks of code to search and destroy this save my bacon a lot!) I do see warnings on the Internet at large however that any form of CompanionObject.method(caseClassInstance: CaseClass) is rife with "code smell" however. Not sure if they actually apply to Scala or not?

There does not however seem to be any way to declare anything in the abstract case class ( TKModel ) that would refer to (at runtime) the proper companion object for a particular instance of a case class. This results in my having to write (and edit) a few method calls that I want standard in each and every case class.

case class Track(id: Long, name: String, statusID: Long) extends TKModel

object Track extends TKModelFactory[Track]

How would I write something in TKModel such that new Track(1, "x", 1).someMethod() could actually call Track.objectMethod()

Yes I can write val CO = MyCompanionObject along with something like implicit val CO: ??? in the TKModel abstract class and make all the calls hang off of that value. Trying to find any incantation that makes the compiler happy for that however seems to be mission impossible. And since I can't declare that I can't reference it in any placeholder methods in the abstract class either.

Is there a more elegant way to simply get a reference to a case classes companion object?

My specific question, as the above has been asked before (but not yet answered it seems), is there a way to handle the inheritance of both the companion object and the case classes and find the reference such that I can code common method calls in the abstract class?

Or is there a completely different and better model?

A companion object does not have access to the instance, but there is no reason the case class can't have a method that calls the companion object.

case class Data(value: Int) {
  def add(data: Data) = Data.add(this,data)
}

object Data {
  def add(d1: Data, d2: Data): Data =  Data(d1.value + d2.value)
}

It's difficult. However you can create an implicit method in companion object. whenever you want to invoke your logic from instance, just trigger implicit rules and the implicit method will instantiate another class which will invoke whatever logic you desired. I believe it's also possible to do this in generic ways.

You can implement this syntax as an extension method by defining an implicit class in the top-level abstract class that the companion objects extend:

abstract class TKModelFactory[T <: TKModel] {
  def objectMethod(t: T)

  implicit class Syntax(t: T) {
    def someMethod() = objectMethod(t)
  }
}

A call to new Track(1, "x", 1).someMethod() will then be equivalent to Track.objectMethod(new Track(1, "x", 1)) .

If you change TKModel a bit, you can do

abstract class TKModel[T <: TKModel] {
  ...
  def companion: TKModelFactory[T]
  def someMethod() = companion.objectMethod()
}

case class Track(id: Long, name: String, statusID: Long) extends TKModel[Track] {
  def companion = Track
}
object Track extends TKModelFactory[Track] {
  def objectMethod() = ...
}

This way you do need to implement companion in each class. You can avoid this by implementing companion using reflection, something like (untested)

lazy val companion: TKModelFactory[T] = {
  Class.forName(getClass.getName + "$").getField("MODULE$").
    get(null).asInstanceOf[TKModelFactory[T]]
}

val is to avoid repeated reflection calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM