开发者

Subclasses and return types

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开发者_Go百科[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?


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜