开发者

Why aren't type parameters allowed in Scala auxiliary constructors?

开发者 https://www.devze.com 2023-04-03 16:00 出处:网络
Say I\'m defining a simple 2D point class in Scala, and I want to be able to construct it with various types:

Say I'm defining a simple 2D point class in Scala, and I want to be able to construct it with various types:

class Point(x:Float, y:Float) {
    this(x:Double, y:Double) = this(x.toFloat, y.toFloat)
    this(x:Int, y:Int) = this(x.toFloat, y.toFloat)
    // etc...
}

I want to boil this down using a template, such as:开发者_JAVA百科

class Point(x:Float, y:Float) {
    this[T](x:T, y:T) = this(x.toFloat, y.toFloat)
}

I know this won't work anyway, since T could be a type for which toFloat isn't defined, but the compiler error I get is:

no type parameters allowed here

Is this just unsupported in Scala? If so, why, and is there any simple way to get around this?


Scala's class constructors (unlike Java's) can't take type parameters, only the class itself can. As to why Scala made this design choice, I assume the main reason is simplicity.

If you want a secondary "builder" method that is generic, the natural thing to do is define it on the companion object. For example,

object Point {
  def build[T : Numeric](x: T, y: T) = {
    val n = implicitly[Numeric[T]]
    new Point(n.toFloat(x), n.toFloat(y))
  }
}

class Point(val x:Float, val y:Float)

val p = Point.build(1, 2) // Companion object's builder
p.x + p.y

Here I've used the Numeric typeclass to get a generic toFloat method.


I played with this for awhile, getting as "close" as...

class Point(x:Float, y:Float) {
  def this[T <: Any { def toFloat: Float }](x:T, y:T) = this(x.toFloat, y.toFloat)
}

...which results in "error: no type parameters allowed here" (just as per the post) and then I realized...

If the initializer could take type parameters it would be ambiguous with the class parameters, if any. Not that this couldn't be worked about in the language specification... but it is a more complex case at the very least. There might also be Java interoperability issues.

Imagine:

class Foo[T](x: T) {
   def this[X](z: X) = ...
}
new Foo[Int](42) // T is Int? X is ...? Or ...?

Personally I wish Scala followed an Eiffel-like pattern (only named constructors or "factory methods"), but alas, that would not be Scala.

Happy coding.

0

精彩评论

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

关注公众号