0

Say I have the following traits and classes:

trait A {
    def foo(): Unit
}

trait B extends A {
    abstract override def foo(): Unit = {
        // Can I determine the name of the concrete class here?
        super.foo()
    }
}

class C extends A {
    def foo() = {
        println("C::foo()")
    }
}

val c = new C with B
c.foo()

Is there a way from within trait B that I can determine the name for the concrete class in which it has been instantiated? i.e. C

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
user79074
  • 4,937
  • 5
  • 29
  • 57
  • 2
    *Is there a way from within trait B that I can determine the name for the concrete class in which it has been instantiated? i.e. C* `B` is not instantiated in `C`. – Dmytro Mitin Aug 09 '20 at 12:58
  • 3
    Did you mean `val c = new C with B`? – Dmytro Mitin Aug 09 '20 at 13:06
  • 1
    Well, I believe you can call `this.getClass.getName` however, why do you want to have the class name? What do you want to do with that information? – Luis Miguel Mejía Suárez Aug 09 '20 at 13:09
  • 1
    Does this answer your question? [How can I easily get a Scala case class's name?](https://stackoverflow.com/questions/2656364/how-can-i-easily-get-a-scala-case-classs-name) – Tomer Shetah Aug 09 '20 at 13:15
  • 2
    Frankly, this just sounds like a bad idea to start with. If your traits need to know about the classes that extend them, then your design is broken. – Matthias Berndt Aug 09 '20 at 13:23
  • 1
    @MatthiasBerndt, I disagree with you in that specific case. Usually this scenario is very common for logging. You place the mutual code in a trait, but when reading the logs it is very important to know who is the final actor. – Tomer Shetah Aug 09 '20 at 13:34
  • 2
    But the ”final actor“ is not C in this case, it's an anonymous class. – Matthias Berndt Aug 09 '20 at 13:48

2 Answers2

0

Try .getClass.getSuperclass.getSimpleName

trait A {
  def foo(): Unit
}

trait B extends A {
  abstract override def foo(): Unit = {
    println("B is instantiated in " + getClass.getSuperclass.getSimpleName)
    super.foo()
  }
}

class C extends A {
  def foo() = {
    println("C::foo()")
  }
}

val c = new C with B
c.foo()
//B is instantiated in C
//C::foo()
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
0

Let's modify your code a bit, as it does not compile. When calling super.foo from B, you get an exception since it is not implemented.

package test

object HelloWorld1 {
  trait A {
    def foo(): Unit
  }

  trait B extends A {
    override def foo(): Unit = {
      println(getClass.getName)
      // Can I determine the name of the concrete class here?
    }
  }

  class C extends B {  }

  class D extends B { }

  def main(args: Array[String]): Unit = {
    val c = new C
    c.foo()
    val d = new D
    d.foo()
  }
}

Given that code, you can call getClass.getName which will provide a string, constructed from the full package name, and class of the current.

In the given example, you'll get:

test.HelloWorld1$C
test.HelloWorld1$D

If you take classes C and D, outside of HelloWorld1, you'll get:

C
D

If you want to get only C and D in the first option, i.e. inside HelloWorld1, you can call to getClass.getSimpleName instead of getClass.getName

There is another option. You can also use getClass.getCanonicalName which will replace the $ with ..

Tomer Shetah
  • 8,413
  • 7
  • 27
  • 35