Scala: how to refer to the type of an extending class in a superclass?

自古美人都是妖i 提交于 2020-01-23 02:18:46

问题


Is there a way to define a type T in Parent such that T will always become the actual type of the extending class (in this case Child)?

In Parent, I want to enforce/declare T to be always the extending type, as if I would have written type T="type_of_the_extending_class" in each actual extending class without actually writing down the lines type T=Child1 in Child1 etc.

So Child1's method only should accept Child1 objects as parameter and Child2's method should only accept Child2 objects. Is there a simpler way to enforce this? Is there a way without writing type T=ChildX in each ChildX class ? Is there a way without this boilerplate?

I've been searching for a solution in Scala books but did not find any.

abstract class Parent{
  type T<:Parent
  def method(t:T) 
}

class Child1 extends Parent{
  type T=Child1
  override def method(t:T)=t.child1method
  def child1method=println("child1's method")
}

class Child2 extends Parent{
  type T=Child2
  override def method(t:T)=t.child2method
  def child2method=println("child2's method")
}

回答1:


The standard solution to this problem is F-bounded polymorphism (which isn't Scala-specific—you'll find it used in Java, etc.):

trait Parent[T <: Parent[T]] {
  def method(t: T)
}

class Child1 extends Parent[Child1] {
  def method(t: Child1) = println("child1's method")
}

class Child2 extends Parent[Child2] {
  def method(t: Child2) = println("child1's method")
}

As a side note, there's been some grumbling about F-bounded polymorphism in the Scala community—Kris Nuttycombe for example says it's "tricky to get right and causes typing clutter in the codebase", and I've personally found that I use it less and less often after several years of writing Scala. When your program architecture leads you to need this kind of inheritance, though, it's exactly the right tool for the job.

The problem with this.type (mentioned in the comments) is that it won't allow you to do most of the things you'd reasonably want to do—it's too specific:

scala> abstract class Parent {
     |   def method(t: this.type)
     | }
defined class Parent


scala> class Child1 extends Parent {
     |   def method(t: this.type) = println("child1's method")
     | }
defined class Child1

scala> val a = new Child1
a: Child1 = Child1@19517e9a

scala> val b = new Child1
b: Child1 = Child1@5737e545

scala> a.method(b)
<console>:12: error: type mismatch;
 found   : b.type (with underlying type Child1)
 required: a.type
              a.method(b)
                       ^

The only argument we can pass to a.method is a itself.



来源:https://stackoverflow.com/questions/21699425/scala-how-to-refer-to-the-type-of-an-extending-class-in-a-superclass

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!