Question

I have abstract class A

abstract class A{

def this(obj:Object){
  this()
  obj match{
    case s:String => stringMethod(s)
    case n:Int => intMethod(n)
  }

  def stringMethod(s:String)

  def intMethod(n:Int)
}

and I have a class that extends this class

class B(obj:Object) extends A(obj){
  var s:String = null

  def stringMethod(s:String){
    this.s = s
  }

  def intMethod(n:Int){
    this.s = n.toString
  }
}

The point of this class is to instantiate an object and its variables depending on the class type of the object used to instantiate it but the problem is that when the abstract constructor is called, the default constructor of object which is extending the abstract object is somehow being called after. This alters the value of var s back to null.

This a really simple implementation of my classes and I have more variables in class B and more logic inside intMethod and stringMethod.

I realize this might be a completely wrong way of doing this, so if there is a better way please let me know.

Was it helpful?

Solution

The body of a super class is always executed before the body of a sub class. In your case A calls stringMethod or intMethod first, then finally B's body is executed, assign null to s. If you remove that assignment, it should work:

abstract class A{
  def this(obj:Object){
    this()
    obj match{
      case s:String => stringMethod(s)
      case n:Int => intMethod(n)
    }
  }

  def stringMethod(s:String)

  def intMethod(n:Int)
}

class B(obj:Object) extends A(obj){
  var s:String = _ // !

  def stringMethod(s:String){
    this.s = s
  }

  def intMethod(n:Int){
    this.s = n.toString
  }
}

val b = new B("foo")
b.s

Neverless, the style is problematic. Here are two alternatives:

trait A {
  def obj: Any
  def s: String
}

class B(val obj: Any) extends A {
  val s = obj match {
    case i: Int    => i.toString
    case x: String => x
    case x         => throw new IllegalArgumentException(x.toString)
  }
}

Or better statically checked:

object B {
  def apply(i: Int   ): B = new B(i, i.toString)
  def apply(s: String): B = new B(s, s)
}
class B private(val obj: Any, val s: String) extends A

B(1.0) // not allowed
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top