In Scala v 2.7.7
I have a file with
class Something[T] extends Other
object Something extends OtherConstructor[Something]
This throws
Thanks for the answers
object Something extends OtherConstructor[Something[_]]
seems to be compiling (although I have yet to run/test that :-))
@oxbow_lakes, I've followed your advice - of avoiding the type system - till now but I've got to do it!!! I've been studying existential types, type-erasure and all that but its still not in my grasp :-(
An object has to have a concrete type. The Scala object contruct is not a exception to this rule.
A valid definition is
object Something extends OtherConstructor[Something[T]] { }
where T
is some concrete type.
You can solve the general problem of needing object Foo[T]
by moving the type parameter to the methods in object Foo
:
class Foo[T](t1: T, t2: T)
object Foo {
def apply[T](x: T): Foo[T] = new Foo(x, x)
def apply[T](x: T, y: T): Foo[T] = new Foo(x, y)
}
If you really need one object per T, you can make a class, and have the type-free companion return it from apply.
class Foo[T](t1: T, t2: T)
class FooCompanion[T] {
def apply(x: T): Foo[T] = new Foo(x, x)
def apply(x: T, y: T): Foo[T] = new Foo(x, y)
}
object Foo {
def apply[T] = new FooCompanion[T]
}
object demo extends App {
val x: Foo[Double] = Foo.apply.apply(1.23) // this is what is really happening
val y: Foo[Int] = Foo[Int](123) // with the type both apply calls are automatic
}
Note this will re-construct the Foo[T] companion on each call so you would want to keep it light and stateless.
An explicit solution the the problem above:
class Other
class OtherConstructor[O <: Other] {
def apply(o: O): O = o // constructor 1 in base class
}
class Something[T](value: T) extends Other
class SomethingConstructor[T] extends OtherConstructor[Something[T]] {
def apply(o: T, s: String) = new Something[T](o) // constructor 2 in subclass
}
object Something {
def apply[T] = new SomethingConstructor[T] // the "constructor constructor" method
}
object demoX extends App {
val si = new Something(123)
val sd = new Something(1.23)
val si1: Something[Int] = Something[Int](si) // OtherConstructor.apply
val sd1: Something[Double] = Something[Double](1.23, "hello") // SomethingConstructor[Double].apply
}
You could use:
object Something extends OtherConstructor[Something[_]]
You will of course be restricted by having an existential type with no upper bound in place instead of a concrete type. This solution may not make sense and you might need one object per concrete type T
, for those T's which you care about, e.g.
object StringSomething extends OtherConstructor[Something[String]]
But then this has the (possible) disadvantage that StringSomething
is not the companion object of Something
.
However, my advice would be don't start messing about designing generic APIs (especially self-referential ones like the above) unless you really, really know what you are doing. It will almost certainly end in tears and there are plenty of CORE Java API's which are terrible because of the way generics have been added (the RowSorter
API on JTable
being one example)