opensas
opensas

Reputation: 63555

scala: defining a trait and referencing the corresponding companion object

I'm trying to define a trait that uses the corresponding companion object, that is, the componion object of the class using the trait.

for example, I have:

:paste

class Parent {
  def callMyCompanion = print(Parent.salute)
}

object Parent {
  def salute = "Hello from Parent companion object"
}

class Child extends Parent {

}

object Child {
  def salute = "Hello from Child companion object"
}

And then I create a parent object:

scala> val p = new Parent()
p: Parent = Parent@1ecf669

scala> p.callMyCompanion
Hello from Parent companion object

But with a child:

scala> val c = new Child()
c: Child = Child@4fd986

scala> c.callMyCompanion
Hello from Parent companion object

I'd like to get: Hello from Child companion object

How can I achieve it???

-- edit to clarify

Thanks for your responses, but in this case callMyCompanion is a dummy method I created just to explain myself, I'm trying to reuse the parent method without having to override it in every class that implements it...

The solution I've found so far was to implement an instance method that uses the companion obejct...

Upvotes: 4

Views: 13101

Answers (4)

drexin
drexin

Reputation: 24403

As I already wrote in the comments, maybe typeclasses can help you here:

trait Greeter[T] {
  def salute: Unit
}
object Greeter {
  implicit def anyToGreeter[A](x: A) = new {
    def salute(implicit greeter: Greeter[A]) = greeter.salute
  }
}

class Foo
class Bar extends Foo

implicit object FooGreeter extends Greeter[Foo] {
  def salute = println("Hello from FooGreeter.")
}
implicit object BarGreeter extends Greeter[Bar] {
  def salute = println("Hello from BarGreeter.")
}

With this I get the following output:

scala> import Greeter._
import Greeter._

scala> new Foo().salute
Hello from FooGreeter.

scala> new Bar().salute
Hello from BarGreeter.

Upvotes: 5

opensas
opensas

Reputation: 63555

The solution I've found so far was to add a reference to the companion object in the class, so that every instance variable can get to the companion object of it's class

That way, I only have to override the method to get a reference to the companion object...

To do that I had to implement a ParentCompanion trait...

But I don't need to override callMyCompanion, or any other method that needs access to the companion object.

It all would be much simpler if I could get a reference of the companion object via reflection...

the code is something like this

:paste

trait ParentCompanion {
  def salute: String
}

class Parent {
  def callMyCompanion = print(companion.salute)
  def companion: ParentCompanion = Parent
}

object Parent extends ParentCompanion {
  def salute = "Hello from Parent companion object"
}

class Child extends Parent {
  override def companion = Child
}

object Child extends Companion {
  def salute = "Hello from Child companion object"
}

Upvotes: 6

Frank
Frank

Reputation: 10571

The main problem with actually having access to the companion object without knowing which one it is, is that you basically have a AnyRef only, which is not very helpful at all.

Another approach would be to use structural typing. I assume that all your different companion objects will have something in common (like the salute you captured in your ParentCompanion trait). Then you can do the following:

class Parent {
  val companion : {
    def salute : String 
  } = Parent
  def foo = println(companion.salute)
}
object Parent {
  val salute = "Parent Companion"
}
class Child extends Parent {
  override val companion = Child
}
object Child {
  val salute = "Child Companion"
}

Given this, every sub-class can override the companion attribute to point to its corresponding companion object, as long as it satisfies the structural type given in Parent (i.e. it has to have a salute in this case). And you can then call this method on your companion, like this:

scala> (new Parent).foo
Parent Companion

scala> (new Child).foo
Child Companion

Upvotes: 1

Judge Mental
Judge Mental

Reputation: 5239

This request is tantamount to static overriding. Such a thing does not exist in scala, AFAIK, but you could include an instance method override in Child that would call its companion object for the message. Something tells me you don't want to do that.

Upvotes: 2

Related Questions