Sometimes I come across a situation where I specifically want to restrict what can be sent to the function, but accept almost any other kind. Is this possible in Scala? For example, this code deals with my issue at runtime - accepting any type T except Option objects. Could the compiler catch it? Thank you
def apply[T:TypeTag](t: T): TaggedOption[T] =
t match {
case o: Option[_] =>
// ensure this can't be created
throw new Exception("This function doesn't work with Options")
case other =>
TaggedOption_(Some(t), PowerTag[T])
}
It is possible to restrict the type parameter:
scala> trait <:!<[A, B]
defined trait $less$colon$bang$less
scala> implicit def nsub[A, B] : A <:!< B = null
nsub: [A, B]=> <:!<[A,B]
scala> implicit def nsubAmbig1[A, B >: A] : A <:!< B = ???
nsubAmbig1: [A, B >: A]=> <:!<[A,B]
scala> implicit def nsubAmbig2[A, B >: A] : A <:!< B = ???
nsubAmbig2: [A, B >: A]=> <:!<[A,B]
scala> def notOption[A](a: A)(implicit ev: A <:!< Option[_]) = a
notOption: [A](a: A)(implicit ev: <:!<[A,Option[_]])A
scala> notOption(1)
res0: Int = 1
scala> notOption(List(""))
res1: List[String] = List("")
scala> notOption(Option(1))
<console>:14: error: ambiguous implicit values:
both method nsubAmbig1 of type [A, B >: A]=> <:!<[A,B]
and method nsubAmbig2 of type [A, B >: A]=> <:!<[A,B]
match expected type <:!<[Option[Int],Option[_]]
notOption(Option(1))
^
scala> notOption(Some(1))
<console>:14: error: ambiguous implicit values:
both method nsubAmbig1 of type [A, B >: A]=> <:!<[A,B]
and method nsubAmbig2 of type [A, B >: A]=> <:!<[A,B]
match expected type <:!<[Some[Int],Option[_]]
notOption(Some(1))
^
scala> notOption(None)
<console>:14: error: ambiguous implicit values:
both method nsubAmbig1 of type [A, B >: A]=> <:!<[A,B]
and method nsubAmbig2 of type [A, B >: A]=> <:!<[A,B]
match expected type <:!<[None.type,Option[_]]
notOption(None)
^
The implicits make the Option
case ambiguous. For a more detailed explanation on how the code is supposed to work, see the following thread on scala-user.
Note: this is NOT a solution to your question, but a possible solution to your problem.
You could handle Option objects by unwrapping them first.
def apply[T:TypeTag](t: T): TaggedOption[T] =
t match {
case Some(x) =>
apply(x)
case None => TaggedNone // or whatever
case other =>
TaggedOption_(Some(t), PowerTag[T])
}
}