Scala Existential Types and Salat

2012-08-06 / All Blog posts

For Scala programmers, the term 'existential types' does not refer to philosophers, or even authentic people. Ironically, most of the discussions of Scala's existential types that I found are be too abstract to be useful to me. I learn by doing; rarely do I learn from reading an abstract treatise. I guess this means that I could be labelled an existentialist.

Section 31.3 of Programming in Scala has some good information on Scala's existential types. Existential types is an abstraction of Java types, and abstraction is the antithesis of existentialism... aaaanyway, here is a sentence I stole from the book:
Iterator[_] means the same thing as Iterator[T] forSome { type T }

forSome is the keyword which tells the compiler that an existential type is being defined. This becomes useful if upper and/or lower bounds are used to define the type. For example, you can use a lower bound to specify that the type must be a subclass of PubSubAction with the following existential type:

T forSome { type T <: PubSubAction }

That is a lot of characters to type, so let's give this type a name:

type PubSubActionSubclass = T forSome { type T <: PubSubAction }

We can also define a type to help us with SalatDAO:

type SalatObject = T forSome { type T <: AnyRef }

Now lets use SalatObject as the parametric type for an invocation of Manifest.classType():

val mot = Manifest.classType[SalatObject](msg.getClass)

This is useful because the manifest can be passed to a SalatDAO constructor, which will create a DAO object for whatever type is supplied. In the following code, PubSubActionClass is just used to guarantee that the msg parameter is of the correct type; SalatDAO's constructor is defined to accept all subclasses of AnyRef.

import com.novus.salat.global.ctx

abstract class PubSubAction

object PubSubAction {
  def makeDAO[PubSubActionSubclass](msg: PubSubActionSubclass)
                              (implicit coll: MongoCollection) = {
    val mot = Manifest.classType[SalatObject](msg.getClass)
    val mid = Manifest.classType[Int](classOf[Int])
    new SalatDAO(coll)(mot, mid, ctx){}
  }
}

Now you know that you do not have to hard-code the creation of a DAO for every PubSubAction subclass. You can examine the source code for SalatDAO if you would like to learn more.

Assuming that psaMsg is an instance of a PubSubActionSubclass, you could call insert() as follows to do a generic insert. Because Salat has multiple methods called insert(), there is not enough type information for Scala to disambiguate the method reference unless the returned value from the single insert is stored in a variable, and that variable's type is provided:

val ignoredIndex: Option[Int] = makeDAO.insert(psaMsg)

There is only one variant of insert() which accepts a collection, so the reference is not ambiguous and the return value can be ignored:

dao.insert(Seq(psaMsg, psaMsg2, psaMsg3), WriteConcern.Normal)

comments powered by Disqus