Yes, Scala allows you to do this solely based on language constructs, without using external DI frameworks such as Guice. To illustrate this, consider the following example (this example borrows heavily from the Jonas Bonér blog-post linked in the question):
package di.example
import play.api.libs.ws.WSClient
trait WSClientComponent {
val wsClient: WSClient
}
NotificationService is a service into which WSClient is to be injected.
package di.example
trait NotificationServiceComponent {this: WSClientComponent =>
val notificationService: NotificationService
class NotificationService{
def getNotifications = wsClient.url("some-url")
}
}
Next, ComponentRegistry is the "module" object to wire our dependencies together.
package di.example
import play.api.libs.ws.{WS, WSClient}
object ComponentRegistry extends WSClientComponent with NotificationServiceComponent {
override val wsClient: WSClient = WS.client
override val notificationService: NotificationService = new NotificationService
}