Ivan
Ivan

Reputation: 64227

Can't I define defaults if I define multiple overloaded constructors in Scala?

I've defined multiple constructors, with some default argument values in all of them. Looks correct (I can't see any ambiguity), but Scala (2.8) compiler complains:

multiple overloaded alternatives of constructor define default arguments

Does it mean that I can't define default values for overloaded constructors at all?

Let me illustrate the situation (primitivized, of course, but illustrative):


class A(subject : Double, factor : Int = 1, doItRight : Boolean = true) {

  def this (subject : Int, factor : Int = 1, doItRight : Boolean = true) = {
    this(subject.toDouble , factor, doItRight)
  }

  def this (subject : String, factor : Int = 1, doItRight : Boolean = true) = {
    this(subject.toDouble , factor, doItRight)
  }

  def this () = {
    this(defaultSubject)
  }

}



Upvotes: 16

Views: 3849

Answers (3)

Profiterole
Profiterole

Reputation: 187

Yes, that's not convenient, you'll need to do without default arguments in your auxiliary constructors like:

class X(n: Int, verbose: Boolean = false) {

  def this(n: String, verbose: Boolean) = this(
      Integer.parseInt(n),
      verbose
  )

  def this(n: String) = this(n, false)
}

Mind though that inline (within a function) with default arguments different from each other you can do that:

def main(args: Array[String]): Unit = {

    class Y(n: Int, dummyImplicit: DummyImplicit = null, verbose: Boolean = false) {

        def this(n: String, verbose: Boolean = false) = this(
            Integer.parseInt(n), 
            verbose = verbose
        )
    }
}

Upvotes: 0

Kevin Wright
Kevin Wright

Reputation: 49705

Taken straight from the compiler's source code:

// only one overloaded alternative is allowed to define default arguments

In general, I wouldn't advise that you mix overloading and defaults. Even if there's no conflict it can make your code harder to read.

UPDATE

Since you added code, it's clear now that you don't want/need to override the default values for each secondary constructor. In your particular case, I might even question the need for those extra constructors at all; Int=>Double is already available for you as an implicit conversion and String=>Double looks like you might be perverting the type system :)

Also... As an alternative to overloaded constructors, you can define just the primary constructor with defaults, then overload the apply method of the companion object and use that as a factory. This is of course completely optional, but it's rapidly becoming established as a pattern through the use of case classes.

Upvotes: 11

Mia Clarke
Mia Clarke

Reputation: 8204

The overloading fails because you (unnessesarily) define multiple constructors with default values. Do this instead:

class A(subject : Double, factor : Int = 1, doItRight : Boolean = true) {

  def this (subject : Int) = {
    this(subject.toDouble)
  }

  def this (subject : String) = {
    this(subject.toDouble)
  }

  def this () = {
    this(defaultSubject)
  }
}

Upvotes: 4

Related Questions