Alex Rivera | Logout

Is it possible in Scala to force the caller to specify a type parameter for a polymorphic method?

Asked 2010-12-09T22:47:10.450
14
//API
class Node
class Person extends Node

object Finder
{
  def find[T <: Node](name: String): T = doFind(name).asInstanceOf[T]
}

//Call site (correct)
val person = find[Person]("joe")

//Call site (dies with a ClassCast inside b/c inferred type is Nothing)
val person = find("joe")

In the code above the client site "forgot" to specify the type parameter, as the API writer I want that to mean "just return Node". Is there any way to define a generic method (not a class) to achieve this (or equivalent). Note: using a manifest inside the implementation to do the cast if (manifest != scala.reflect.Manifest.Nothing) won't compile ... I have a nagging feeling that some Scala Wizard knows how to use Predef.<:< for this :-)

Ideas ?

Edit
Report

1 Answer

8

Miles Sabin posted a really nice solution for this problem on the scala-user mailing list. Define a NotNothing type class as follows:

sealed trait NotNothing[T] { type U }                                          
object NotNothing {
   implicit val nothingIsNothing = new NotNothing[Nothing] { type U = Any }
   implicit def notNothing[T] = new NotNothing[T] { type U = T }           
}

Now you can define your Finder as

object Finder {
   def find[T <: Node : NotNothing](name: String): T = 
      doFind(name).asInstanceOf[T]
}

If you try to invoke Finder.find without a type parameter, you'll get a compile-time error:

error: ambiguous implicit values: both method notNothing in object $iw of type [T]java.lang.Object with NotNothing[T]{type U = T} and value nothingIsNothing in object $iw of type => java.lang.Object with NotNothing[Nothing]{type U = Any} match expected type NotNothing[T] Finder.find("joe")

This solution is far more general than the ones proposed in my other answers. The only drawback I can see is that the compile-time error is pretty opaque, and the @implicitNotFound annotation doesn't help.

answered 2011-01-02T19:51:14.293

Your Answer