Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

trying to find simpler way to reference type of subclass from trait

so, here's a bit of a contrived example:

trait MyTrait { 
  type T <: MyTrait
  val listOfT:List[T]
  def getFirst:T
  //def getOne:T = if( listOfT.length > 0 ) { getFirst } else { this }
}

class MyClass extends MyTrait {
  type T = MyClass
  override val listOfT:List[T] = List[MyClass](this)
  override def getFirst:T = listOfT.head
}

The question sort of has two parts:

Is there some other way to do this where the return types in MyClass could just be "MyClass" instead of having to specify "type T = MyClass" ? Basically I want to be able to add this trait to a class without really having to have the subclass change its implementation significantly or think about the type system... to just return members of itself, and have the trait accept anything as long as it is covariant on the subtype. Does this even make sense?

in MyTrait, if uncommented, getOne method will give an error "type mismatch:" found : MyTrait.this.type (with underlying type MyTrait) required: MyTrait.this.T

If I were to change the return type to this.type, I'd get the opposite found/required type mismatch. Either return value actually has the same type (and is actually the same object).

What's the correct way to handle these kinds of situations?

like image 942
nairbv Avatar asked Oct 25 '25 02:10

nairbv


1 Answers

Is this what you want?

trait MyTrait[T <: MyTrait[T]] { self: T =>
  val listOfT: List[T]
  def getFirst: T
  def getOne: T = if (listOfT.length > 0) getFirst else self
}

class MyClass extends MyTrait[MyClass] {
  override val listOfT: List[MyClass] = List[MyClass](this)
  override def getFirst: MyClass = listOfT.head
}

It gets rid of type T = MyClass (allowing you to just put MyClass in a return type) and fixes the compile error in the definition of getOne.

like image 113
dhg Avatar answered Oct 26 '25 23:10

dhg