Subclasses and return types

怎甘沉沦 提交于 2019-12-24 08:43:21

问题


let's say I wanted to have something like the following:

abstract class PDF[T, S <: PDF[T, _]] {
  def fit(obs: Seq[T], weights: Seq[Double]): S
}

class PDFGaussian(val mu: Double, val Sigma: Double) extends PDF[Double, PDFGaussian] {
  def fit(obs: Seq[Double], weights: Seq[Double]): PDFGaussian =
    new PDFGaussian(...) // bla bla bla
}

So, basically, what I want is to have the fit function to return an instance of the type of its enclosing class which obviously must be a subclass of PDF[T]. However, instead of having to use the double parameterization PDF[T, S <: PDF[T, _]] I'd rather go with only one type parameter like so:

abstract class PDF[T] {
  def fit[S <: PDF[T]](obs: Seq[T], weights: Seq[Double]): S
}

class PDFGaussian(val mu: Double, val Sigma: Double) extends PDF[Double] {
  def fit[S <: PDF[_]](obs: Seq[Double], weights: Seq[Double]): S =
    new PDFGaussian(...) // bla bla bla
}

If I do this, however, the compiler yells at me for returning PDFGaussian instead of S. Since I'm obviously missing some important fact about scala's type system here could you please clarify what I'm doing wrong and show me how to do it with only one type parameter?


回答1:


Your first solution is pretty good, IMHO. But let's talk about the questions. First, about what is wrong here:

abstract class PDF[T] {
  def fit[S <: PDF[T]](obs: Seq[T], weights: Seq[Double]): S
}

class PDFGaussian(val mu: Double, val Sigma: Double) extends PDF[Double] {
  def fit[S <: PDF[_]](obs: Seq[Double], weights: Seq[Double]): S =
    new PDFGaussian(...) // bla bla bla
}

Let's say I have

class FooBar extends PDF[Double] { ... }

And I do:

val pdfg = new PDFGaussian(1.0, -1.0)
val foobar = pdfg.fit[FooBar](List(0.5, 0.75), List(4, 2))

So, I'm telling the compiler that I want S to be FooBar, but you are returning PDFGaussian! That's what the compiler is complaining about.

So, how to solve it? Well... tough. :-) How about this:

abstract class PDF[T] {
  type S <: PDF[T]
  def fit(obs: Seq[T], weights: Seq[Double]): S
}

class PDFGaussian(val mu: Double, val Sigma: Double) extends PDF[Double] {
  type S = PDFGaussian
  def fit(obs: Seq[Double], weights: Seq[Double]): S =
    new PDFGaussian(...) // bla bla bla
}

It's a bit more verbose, but it keeps PDF type signature cleaner.



来源:https://stackoverflow.com/questions/5387602/subclasses-and-return-types

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