3
votes

Trait in scala is something like interface in Java or abstract class. Thus it is not possible to get an instance directly from a trait. But, I found a way to instantiate a trait. Here is what i do:

trait B {
  def bId = 1
}

trait A { self: B =>
  def aId = 2
}

val a = new A with B // The type of a is "A with B", a's value is $anon$1@6ad16c5d

and the following:

trait User {
  def name: String
}

trait DummyUser extends User {
  override def name: String = "foo"
}

trait Tweeter { self: User =>
  def tweet(msg: String) = println(s"$name: $msg")
}

val t = new Tweeter with User // This doesn't compile
val t = new Tweeter with User with DummyUser // This does work!
// t: Tweeter with User with DummyUser = $anon$1@72976b4
t.tweet("hello")  // result is: "foo: hello"

Both segments of code are working on Scala 2.12. In the all of them, there are only traits! No class at all.

How can trait work in this way?

1
It's actually much simpler than that. new B {} - jwvh

1 Answers

6
votes

This instantiation like Java's Anonymous Classes instantiation, so when new Tweeter with User it's actually create a new anonymous instance for Tweeter with User Anonymous Classes.

And new Tweeter with User for this not compile, since it's losing the implementation of name method. actually you need to implement it like:

  val t = new Tweeter with User {
    override def name: String = "hello world"
  }

for new Tweeter with User with DummyUser you just need to state it as new Tweeter with DummyUser, Since DummyUser is subtype of User.

And there is a cake pattern in Scala for how to use self type to implement Dependency Injection.