Migrating to Singletons

I want to use Akka’s Typed Actors in my application, and as far as I understood, there are basically two approaches to do that:

  1. Using DSL and singleton objects or
  2. extending from AbstractBehavior[T].

The first version looks appealing to me but appears to be limited to singleton objects (since it is built on the apply method.

This is a (simplified) class hierarchy I use in my application:

abstract class AbstractWindow[Component] protected(private val _view: View) {
  protected def this() {
    this(new View())
  }
  
  def setTitle(title: String): Unit = _view.setTitle(title)

  def openWindow(): Unit = {
    _view.open()
  }
}

class ApplicationWindow(mainView: View) extends AbstractWindow[Application](mainView)

If I was to extend from AbstractBehavior[T] I had to migrate AbstractWindow to a trait but then I cannot pass mainView to it.

If I was to use the DSL I had to migrate ApplicationWindow to a singleton object. I then still could extend from AbstractWindow but again, I had no way to pass mainView to it since there is no constructor for an object (or is there)?

Any suggestions what I could do?

In general, I’d probably recommend taking questions like this to the Akka Forum, where you are going to find a lot more expertise in Akka practice.

That said – there are ways around this. A fairly conventional one would be to define AbstractWindow as a trait, and instead of passing the View as a constructor parameter, instead just define it as an abstract member:

def _view: View

and then have ApplicationWindow define that field. Yes, that doesn’t allow you to do the private thing, but in my experience private is used rather less in Scala than in, say, Java, and tends not to be as important.

(Note that Scala 3 will likely allow you to pass constructor parameters to traits, but that doesn’t help you right now.)

I decided to post it here because to me it sounded more like a Scala than an Akka question.

I already thought of the version with the abstract member in the trait, but how can I set this value? I suppose I need to do this in the body of the singleton since it is final, but the only way to pass it from outside would be the apply method.

You set the value in ApplicationWindow:

trait AbstractWindow[Component] {
  def _view: View
}
class ApplicationWindow(mainView: View) extends AbstractWindow[Application](mainView) {
  val _view = mainView
}

The details vary, but this is a really common pattern when you’re using inheritance…

No. object has factory methods, but they return closures and each closure can close over different state.

Let’s take an example from Akka documentation:

object HelloWorldBot {

  def apply(max: Int): Behavior[HelloWorld.Greeted] = {
    bot(0, max)
  }

  private def bot(greetingCounter: Int, max: Int): Behavior[HelloWorld.Greeted] =
    Behaviors.receive { (context, message) =>
      val n = greetingCounter + 1
      context.log.info2("Greeting {} for {}", n, message.whom)
      if (n == max) {
        Behaviors.stopped
      } else {
        message.from ! HelloWorld.Greet(message.whom, context.self)
        bot(n, max)
      }
    }
}

Invoking HelloWorldBot.apply(5) invokes HelloWorldBot.bot(0, 5) which returns a Behavior[HelloWorld.Greeted] that closes over the parameters passed to HelloWorldBot.bot.

Alternatively you could change the HelloWorldBot.bot method to a class extending AbstractBehavior[HelloWorld.Greeted] having the paramters of HelloWorldBot.bot moved to its constructor, but such style is discouraged in Akka Typed.