In Scala, how can I subclass a Java class with multiple constructors?

JavaScalaConstructorMultiple Constructors

Java Problem Overview


Suppose I have a Java class with multiple constructors:

class Base {
    Base(int arg1) {...};
    Base(String arg2) {...};
    Base(double arg3) {...};
}

How can I extend it in Scala and still provide access to all three of Base's constructors? In Scala, a subclass can only call one of it's superclass's constructors. How can I work around this rule?

Assume the Java class is legacy code that I can't change.

Java Solutions


Solution 1 - Java

It's easy to forget that a trait may extend a class. If you use a trait, you can postpone the decision of which constructor to call, like this:

trait Extended extends Base {
  ...
}

object Extended {
  def apply(arg1: Int) = new Base(arg1) with Extended
  def apply(arg2: String) = new Base(arg2) with Extended
  def apply(arg3: Double) = new Base(arg3) with Extended
}

Traits may not themselves have constructor parameters, but you can work around that by using abstract members instead.

Solution 2 - Java

EDIT - this is from a question on the scala mailing list which I thought was duplicated here. My answer relates to providing three different constructors (i.e. replicating the Java design), and not extending the class

Assuming that each of your constructors ultimately create the state S of the object, create a companion object with "static" methods to create this state

object Base {
  private def stateFrom(d : Double) : S = error("TODO")
  private def stateFrom(s : Str) : S = error("TODO")
  private def stateFrom(i : Int) : S = error("TODO")
} 

Then create a private constructor taking the state and (public) overloaded constructors which defer to the primary constructor

import Base._
class Base private(s : S) { //private constructor takes the state
  def this(d : Double) = this(stateFrom(d)) 
  def this(str : String) = this(stateFrom(str))
  def this(i : Int) = this(stateFrom(i))
  //etc
}

Solution 3 - Java

I would pick the most generic one (in this case, String) and do the internal conversion yourself if it meets the other criteria.

Although I admit this is not the best solution and something strikes me as wrong about it. :-(

Solution 4 - Java

This is a silly answer that would probably work somewhat but might be too much effort if the Java class has way too many constructors, but:

Write a subclass in Java that implements a constructor that takes all the inputs the various other constructors would and calls the proper constructor of its superclass based on the presence or absence of inputs (via usage of "null" or some sort of sentinel values), then subclass that Java class in Scala and assign the sentinel values as default parameters.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSeth TisueView Question on Stackoverflow
Solution 1 - JavaSeth TisueView Answer on Stackoverflow
Solution 2 - Javaoxbow_lakesView Answer on Stackoverflow
Solution 3 - JavacorsiKaView Answer on Stackoverflow
Solution 4 - JavaJABView Answer on Stackoverflow