3

I have some code like the following:

class Test(var f1 : String) {

    def this(a : Int) {
        this(makeStr(a))
    }

    private def makeStr(a : Int): Unit = {
        "ABC" + a
    }
}

The error I get is: not found: value makeStr.

It seems like the scala compiler cannot see the makeStr method in the constructor. It seems to be quite different from Java where it is doable. Does anyone know what is the right way to initialize the instance fields which requires some methods to compute the values?

Vladyslav
  • 2,018
  • 4
  • 18
  • 44
gdlamp
  • 613
  • 1
  • 6
  • 24

3 Answers3

3

You can't call instance methods before the primary constructor has run. You can declare makeStr as a method in the companion object so you can run it before the primary constructor. Also not that it should return String, not Unit as in your code.

class Test(var f1 : String) {

  def this(a : Int) {
    this(Test.makeStr(a))
  }

  override def toString = s"Test($f1)"
}

object Test{
  private def makeStr(a : Int): String = {
    "ABC" + a
  }
}

new Test(1) //res0: Test = Test(ABC1)

It's a bit more idiomatic to define factory methods in the companion object instead of using multiple constructors though, as the other answers mention.

puhlen
  • 8,400
  • 1
  • 16
  • 31
0

If I understand correctly, you are trying to create a class with multiple constructors. In scala, the best practice is different from Java.

You should first create a class and then its companion object in order to implement different constructors.

//your class
class Test(val f1: String)

//its companion object
object Test {

  def apply(f1: String): Test = new Test(f1)

  def apply(f1: Int): Test = new Test("ABC" + f1)

}

You can simply test the code above by the following code:

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

        val testInt: Test = Test(1)

        val testString: Test = Test("1")

        println(testInt.f1)

        println(testString.f1)

     }
 }
fcat
  • 1,251
  • 8
  • 18
  • you missed the point, I am talking about the ability to call instance method in the constructor argument (ie. the makeStr method) – gdlamp Sep 27 '17 at 15:26
0

I feel in this case that the best solution would be to use factory methods instead of auxi constructor.

So you can define your constructor private and provide factory apply methods in companion object:

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Test private(var f1 : String)
object Test {
      def apply(i: String) =  new Test(i)
      def apply(s:Int) = new Test(makeStr(s))
      def makeStr(s: Int) = {
      "ABC" + s } }

// Exiting paste mode, now interpreting.

defined class Test
defined object Test

For more infor refer

Mahesh Chand
  • 3,158
  • 19
  • 37