I have defined the following trait:
trait Felem[T <: Felem[T]] {
def mul(that: T): T
def square: T = this.mul(this.asInstanceOf[T])
}
I also define a class based on this trait:
class F2elem(val coef: Boolean) extends Felem[F2elem] {
override def square: F2elem = this.mul(this)
...
}
My questions are about the need of "asInstanceOf" in the definition of the "square" method in the trait. If I remove it, I get the following error:
error: type mismatch;
found : Felem.this.type (with underlying type Felem[T])
required: T
def square: T = this.mul(this)
The parameter of mult must be of type T
.
When calling mul(this)
, the this parameter is of type Felem[T]
, which is not and does not conform to T
. There is the additional constraint that T
conforms to Felem[T]
. But this is not what you want, you would need the opposite, Felem[T]
to conform to T
.
On the other hand, in F2elem
, T
is exactly F2elem
, so it typechecks (completley unrelated to one being a trait and the other one a class)
Here is example to show that the definition in Felem
must indeed not typecheck, and that it is possible to have implementors where Felem[T]
does not conform to T
.
class F3elem extends Felem[F2elem] // this is 2, not 3
This declaration is correct, F2elem
which is given for T
satisfies T <: Felem[T]
. However, an inherited t his.mul(this)
in square
would be invalid, mult expect a T
, that is F2elem
, and this is F3elem
. And they are unrelated.
What you probably want is that every Felem
must be like F2elem
, that is that T
must be the type of the actual class. You can enforce this with a self type.
trait Felem [T <: Felem[T]] { this: T => /* your code */ }
When you write that, you state that in every implementation, the type of the implementation must conform to T
. Doing that, it will typecheck, and you will not be allowed to instanciate F3elem above :
error: illegal inheritance; self-type F3elem does not conform to Felem[F2elem]'s selftype F2elem class F3elem extends Felem[F2elem] {
1) In your trait
this
is not an instance of T
:
scala> trait Felem[T <: Felem[T]] {
| def mul(that: T): T = that
| def square: T = this.mul(this.asInstanceOf[T])
| }
defined trait Felem
scala> class F2elem extends Felem[F2elem]
defined class F2elem
scala> class F3elem extends Felem[F2elem]
defined class F3elem
scala> new F3elem()
res1: F3elem = F3elem@2e0b08f1
scala> res1.square
java.lang.ClassCastException: F3elem cannot be cast to F2elem
2) In your class
this
is F2elem
and T
== F2elem
, so this
is T
.
You're using T
as your method's parameter type. This means that whatever the type of T
is will be the type that's required in the method (hence not needing the cast in the class, since its type is what is signified by T
originally).
If you change the type of that
to Felem[T]
, you will not need the cast.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.