Polymorphic Scala return type

后端 未结 2 1233
我在风中等你
我在风中等你 2020-12-14 12:54

I have an abstract Scala class Base which has subclasses Derived1 and Derived2. Base defines a function f() which returns

相关标签:
2条回答
  • 2020-12-14 13:03

    Just to add a small precision about (perfectly good) Travis Brown answer: It's not that C in trait Base[C <: Base[C]] let's you refer to the implementing class; it's just sticking to the convention of writing subclass extends Base[subclass] that let's you do so. There's no way that I know of to refer to this type. To clarify what I mean, this compiles

    trait Base[C <: Base[C]] { def f: C }
    
    case class Derived1(x: Int) extends Base[Derived1] {
      def f: Derived1 = Derived1(x + 1)
    }
    // a Derived2 where f returns Derived1!!
    case class Derived2(x: Int) extends Base[Derived1] {
      def f = Derived1(x + 2)
    }
    

    Now, if all you're going to have as implementations of Base are case classes, you can get this right through a self-type bound:

    trait Base[C <: Base[C]] { self: C => 
      def f: C 
    }
    
    case class Derived1(x: Int) extends Base[Derived1] {
      def f: Derived1 = Derived1(x + 1)
    }
    // a Derived2 where f returns Derived1!!
    // this won't compile now
    case class Derived2(x: Int) extends Base[Derived1] {
      def f = Derived1(x + 2)
    }
    
    0 讨论(0)
  • 2020-12-14 13:09

    Randall Schulz pointed out one of the reasons your current code doesn't work. It is possible to get what you want, though, with F-bounded polymorphism:

    trait Base[C <: Base[C]] { def f: C }
    
    case class Derived1(x: Int) extends Base[Derived1] {
      def f: Derived1 = Derived1(x + 1)
    }
    
    case class Derived2(x: Int) extends Base[Derived2] {
      // Note that you don't have to provide the return type here.
      def f = Derived2(x + 2)
    }
    

    The type parameter on the base trait allows you to talk about the implementing class there—e.g. in the return type for f.

    0 讨论(0)
提交回复
热议问题