1

I believe that in Scala, like in Java, subclass fields are initialized after the super constructor has executed. Given this, I'm struggling to identify how best to create "abstract fields" that can be initialized in my subclass but validated (or used for validation of other fields) in the constructor of my abstract parent class. To give a simple example of what doesn't work:

abstract class ApiClient(contentType: String) {
  val supportedContentTypes: List[String]
  if (!(supportedContentTypes contains contentType)) {
    throw new RuntimeException("Type " + contentType + " not supported")
  }
}

class FacebookClient(contentType: String) extends ApiClient(contentType) {
  override val supportedContentTypes = List("text/xml", "application/xml")
}

val api = new FacebookClient("text/xml") // Throws NullPointerException

This question is much-discussed for Java (e.g. here and here) and the general answer is to put the "abstract fields" in the parent class's constructor. Does this advice hold true for Scala too, or is there a neater alternative I'm missing?

To follow this approach with Scala, my code would look like this:

abstract class ApiClient(contentType: String, supportedContentTypes: List[String]) {
  if (!(supportedContentTypes contains contentType)) {
    throw new RuntimeException("Type " + contentType + " not supported")
  }
}

class FacebookClient(contentType: String) extends ApiClient(
  contentType,
  List("text/xml", "application/xml")) {
}

val api = new FacebookClient("text/xml") // Runs!

Is this the best approach? I haven't seen any examples to the contrary but loading up the super constructor like this doesn't "smell" great to me. Any thoughts gratefully received!

Community
  • 1
  • 1
Alex Dean
  • 15,575
  • 13
  • 63
  • 74

1 Answers1

2

I think that the easiest solution is to make supportedContentTypes in FacebookClient lazy:

class FacebookClient(contentType: String) extends ApiClient(contentType) {
  override lazy val supportedContentTypes = List("text/xml", "application/xml")
}

This should work as expected.


You can also use abstract method - it should also work just fine. But in contrast to Java, much less syntax is involved. You generally need to change val to def and you are done.

tenshi
  • 26,268
  • 8
  • 76
  • 90