Harald
Harald

Reputation: 5093

Plural Singletons for class with generic parameters

Is it possible in Scala to define the singletons for a class with a generic parameter? Yes its the plural, because there must be a singleton for each instance of the generic parameter. This is nonsense in the most general case, I believe, but if the generic parameter is a subtype of something specific, I wonder whether it may work.

As an example consider as the specific supertype of all generic parameters to be this abstract class.

abstract class BaseType[T<:BaseType] {
  val omega:T;
}

The idea is that each implementation has a special value, and this is omega. Now I want a class which has subtypes of BaseType as a generic parameter:

class Thing[T<:BaseType[T]](val v:T, foo:Int);

Because each T has the specific value omega, I would like to have singletons for Thing containing omega and, say, foo=0. I cannot even do

object Thing {
  def OmegaInstance[T<:BaseType[T]] = new Thing(/*what gos here?*/, 0);
}

but even if I could, the OmegaInstance would be new for each call, which I don't want.

Any chance to get this working?

Upvotes: 1

Views: 222

Answers (1)

dk14
dk14

Reputation: 22374

If your input type parameter is not erased you can implement same old lightweight pattern, but with TypeTag as a key:

import scala.reflect.runtime.universe._ 
import scala.collection.concurrent._

object Things {
   class Thing[T] private[Things]() { //private constructor, class itself is still accessable
       //...
   }

   private val map = TrieMap[TypeTag[_], Thing[_]]()

   def Thing[T: TypeTag] = 
          map.getOrElseUpdate(typeTag[T], new Thing[T]).asInstanceOf[Thing[T]] //`asInstanceOf` is safe here

}

Usage examples:

import Things._

scala> Thing[Int]
res2: Things.Thing[Int] = Things$Thing@4472abe8 //new object

scala> Thing[Int]
res3: Things.Thing[Int] = Things$Thing@4472abe8 //same object

scala> Thing[Int]
res4: Things.Thing[Int] = Things$Thing@4472abe8 //same object

scala> Thing[String]
res5: Things.Thing[String] = Things$Thing@4745c8d2 //new object

scala> Thing[String]
res6: Things.Thing[String] = Things$Thing@4745c8d2 //same object

You can instantiate any thing you want with any parameter here. The usage looks almost like just having generic-parameterized object (one singleton for every generic).

Upvotes: 0

Related Questions