Pooya
Pooya

Reputation: 4481

How to solve Illegal inheritance from final class in Scala

I have this code in Scala when I define the a value, Also I call some methods in the object like setStr and it is very useful and amazing. But when I define my AClass as final, compiler will throws an exception as Illegal inheritance from final class. In some cases I should use final classes and this type of method calling after the class initiation is very useful to me, and my question is how to solve this problem

test("Test function call") {
    val a: AClass = new AClass {
        setStr("Pooya")
        func1(this)
    }
}

class AClass { // when I declare the class final, the compiler will raise an error
    private var str:String=""
    def setStr(str:String)={
        this.str=str
    }
    def aMethod() = print(str)
}

def func1(a: AClass) {
    a.aMethod()
}

Upvotes: 2

Views: 4728

Answers (2)

som-snytt
som-snytt

Reputation: 39577

To get final semantics, pass in your initial state to the constructor.

The other mode is to use early definitions. Note that BClass#strs is final.

Final means that when your initializer is done, the value mustn't change.

And lose the mutable state.

But if you love or need mutability, a factory on the companion object can work whatever sanity you require when you build the object.

package inheritthewind

object Test extends App {
  val a = new AClass(new AInit { val str = "Pooya" })
  a.aMethod()
  val b = new {
    val str: String = "Pooya"
  } with BClass
  b.aMethod()
  val b2 = new BClass {
    val str: String = "Pooya"
  }
  b2.aMethod()  // uh no, result is "nulls"
  val c = CClass(new CPrototype { val str = "Pooya" })
  c.aMethod()
  // not allowed
  //val nope = new CClass
}

trait AInit {
  def str: String
}

final class AClass(init: AInit) {
  private final val str: String = init.str
  def aMethod() = Console println str
}

abstract class BClass {
  val str: String
  final val strs = str + "s"
  def aMethod() = Console println strs
}

trait CPrototype extends AInit

final class CClass private() {
  private var str: String = _
  def aMethod() = Console println str
}
object CClass {
  def apply(p: CPrototype): CClass = {
    val res = new CClass
    res.str = p.str
    res
  }
}

And

scala> :javap -pv inheritthewind.BClass
[snip]
  private final java.lang.String strs;
    flags: ACC_PRIVATE, ACC_FINAL

  public abstract java.lang.String str();
    flags: ACC_PUBLIC, ACC_ABSTRACT

  public final java.lang.String strs();
    flags: ACC_PUBLIC, ACC_FINAL

Upvotes: 1

pedrofurla
pedrofurla

Reputation: 12783

When you do new AClass { ... } you are creating an anonymous class that extends this class. When a class is final it cannot be extended.

One way to do what you want is like that:

val a: AClass = new AClass 
import a._
setStr("Pooya")
func1(this)

Following @Vladimir's suggestion, a slightly cleaner way:

val a: AClass = { val a = new AClass 
  import a._
  setStr("Pooya")
  func1(this) 
  a 
}

Now you can repeat that as many times as you want without making setStr ambiguous. For the func1, with its current definition, should't matter if it's in the {} block or not.

Upvotes: 3

Related Questions