Reputation: 4481
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
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
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