Reputation: 2134
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:
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?
Upvotes: 14
Views: 1664
Reputation:
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.
Upvotes: 3
Reputation: 21112
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.
Upvotes: 15