Scala passing type parameters to object

后端 未结 4 1926
北恋
北恋 2021-02-20 09:11

In Scala v 2.7.7

I have a file with

class Something[T] extends Other

object Something extends OtherConstructor[Something]

This throws

相关标签:
4条回答
  • 2021-02-20 09:36

    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 :-(

    0 讨论(0)
  • 2021-02-20 09:39

    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.

    0 讨论(0)
  • 2021-02-20 09:46

    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
    }
    
    0 讨论(0)
  • 2021-02-20 09:53

    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)

    0 讨论(0)
提交回复
热议问题