Is there a way to write object with generic parameters, like that:
object Aaa[T] {
def f(a: T) = a
}
Or, in other words, to have singleton on instance-level, but not on the type level.
I know that I could do the same with:
object Aaa {
def f[T](a: T) = a
}
But what if I have several methods to restrict with single polymorphic type:
object Aaa[T] {
def f1(a: T) = a
def f2(b: T) = b
}
//somewhere in the code:
val a = Aaa[Int]
import a._
f1(5)
f2(6)
someFunction(a)
PS All I want is singleton factory with type-parameter as input (and as a key). Usually it's implemented with Map[TypeTag, Object]
(which requires thread-safety, btw) - looking for more nice solution here. For example with "parametrize method" approach I can't:
trait T1[T] {
def f1(a: T): T
def f2(b: T): T
}
object Aaa extends T1 { //won't compile, have to use class
//some heavy initialization and data here
(1 to 100500000).map(List.empty[T])
def f1[T](a: T) = a
def f2[T](b: T) = b
}
It might be some method that creates a big structure and requires generic type to be specified.
And of course this object may be passed to another function (or value), so single polymorphic type restriction really works.
Yes, that's possible using .asInstanceOf
:
trait AaaImpl[T] {
this: Aaa.type =>
def f(a: T) = a
}
object Aaa extends AaaImpl[Nothing] { // lower bound of T should be here
def apply[T] = this.asInstanceOf[AaaImpl[T]]
}
// Exiting paste mode, now interpreting.
defined trait AaaImpl
defined module Aaa
scala> Aaa[Int].f(5)
res7: Int = 5
scala> Aaa[Double].f(5.0)
res8: Double = 5.0
It's safe to cast here as long as your object doesn't do any other typecasts. asInstanceOf
just copying your type (using AaaImpl[Nothing]
as prototype) but with new type parameter (like case class
's copy
does in values world).
PS Trait's methods will be also available inside Aaa itself, but Nothing
will be used for T
PS2 You may also implement some other traits to pass this object to some external library:
//External
trait SomeAbstractType[T] {
def f(a: T): T
}
def ff[T](x: SomeAbstractType[T]) = x
//Internal
trait AaaImpl[T] { def f(a: T) = a }
object Aaa extends AaaImpl[Nothing] with SomeAbstractType[Nothing] { // lower bound of T should be here
def apply[A] = this.asInstanceOf[AaaImpl[A] with SomeAbstractType[A]]
}
// Exiting paste mode, now interpreting.
defined trait SomeAbstractType
ff: [T](x: SomeAbstractType[T])SomeAbstractType[T]
defined trait AaaImpl
defined module Aaa
scala> ff(Aaa[Int])
res11: SomeAbstractType[Int] = Aaa$@6e18a830
scala> ff(Aaa[Double])
res12: SomeAbstractType[Double] = Aaa$@6e18a830 //same instance
scala> ff(Aaa[Int]).f(5) //different behaviour
res15: Int = 5
scala> ff(Aaa[Double]).f(5.0)
res16: Double = 5.0
Update1. Examples of something cooler than identity:
scala> trait AaaImpl[T] {
def list(a: T) = List(a)
def empty = List[T]()
def square(a:T)(implicit n:Numeric[T]) = n.times(a, a)
}
defined trait AaaImpl
scala> object Aaa extends AaaImpl[Nothing]{ // lower bound of T should be here
def apply[A] = this.asInstanceOf[AaaImpl[A]]
}
defined module Aaa
scala> Aaa[Int].list(5)
res21: List[Int] = List(5)
scala> Aaa[Int].empty
res22: List[Int] = List()
scala> Aaa[Int].square(5)
res23: Int = 25
scala> Aaa[List[Int]].square(5)
<console>:11: error: type mismatch;
found : Int(5)
required: List[Int]
Aaa[List[Int]].square(5)
^
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.