2013-11-17 1 views
3

Я пытаюсь использовать шаблон typeclass в Scala, чтобы пометить все допустимые типы сериализуемых API, чтобы мы могли обеспечить безопасность во время компиляции вокруг того, что мы сериализуем. Наша базовая библиотека принимает AnyRef, что может привести к странным ошибкам, когда явным образом не объявляю тип перед его сериализацией.Как обмануть Scala, чтобы не найти дублирующихся имплицитов для Nothing

Мы разрешаем отправку общедоступной модели, итерации общедоступных моделей, опции общедоступной модели или единицы.

trait PublicModel 
case class UserModel(name: String) extends PublicModel 
sealed class SafeForPublic[-T] 
implicit object PublicModelOk extends SafeForPublic[PublicModel] 
implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]] 
implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]] 
implicit object UnitOk extends SafeForPublic[Unit] 

Этот метод работает хорошо для всех, кроме методов, в которых тип параметра является опцией. Это происходит потому, что None является Option[Nothing], так T = Nothing, который сообщит компилятору искать неявный объект типа SafeForPublic[Nothing] и он найдет как SafeForPublic[PublicModel], а также SafeForPublic[Iterable[PublicModel]]

def boxed[T : SafeForPublic](t: Option[T]) = println("wooohoo!") 

boxed(Some(None)) // works 
boxed(Some(1)) // doesn't compile. Int is not a valid serializable model. 
boxed(Some({})) // works 
boxed(Some(UserModel("ok"))) // works 
boxed(Some(Seq(UserModel("ok")))) // works 
boxed(None) // doesn't compile, duplicate implicits >< 

Любая идея, как я могу обмануть компилятор для не найти дубликаты неявки для Nothing. Я видел, что у Майлза Сабина был трюк, используя:

sealed trait NotNothing[A]{ 
    type B 
} 
object NotNothing { 
    implicit val nothing = new NotNothing[Nothing]{ type B = Any } 
    implicit def notNothing[A] = new NotNothing[A]{ type B = A } 
} 

Но я не мог понять, как его использовать. Halp?

+0

Посмотрите на [этот вопрос] (http://stackoverflow.com/questions/15962743/using-context-bounds-negatively-to-ensure- type-class-instance-is-abs-from-s) для прохода трюка отрицания. Я закончил с родовым классом типа «Не [_]». См. Ответ для получения более подробной информации. – nadavwr

ответ

2

Хорошо, благодаря некоторой помощи от IRC-канала Scala я понял, что для решения этой проблемы были созданы функции LowPriority implicits.

Я использовал это, чтобы исправить это:

sealed class SafeForPublic[-T] 
trait LowPriorityImplicits { 
    implicit object PublicModelOk extends SafeForPublic[PublicModel] 
    implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]] 
    implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]] 
    implicit object UnitOk extends SafeForPublic[Unit] 
} 
object Implicits extends LowPriorityImplicits { 
    implicit object NothingOk extends SafeForPublic[Nothing] 
} 
import Implicits._ 
def boxed[T : SafeForPublic](t: Option[T]) = println("woohoo!") 
boxed(None) // compiles! \o/ 
+0

Не могли бы вы объяснить, почему это решение работает? Я думаю, что имя 'LowPriorityImplicits' не так или иначе особенное, но это также не ясно из вашего ответа. – ziggystar

+0

@ziggystar это специальное правило для наследования имплицитов, посмотрите http://www.scala-lang.org/files/archive/spec/2.11/12-the-scala-standard-library.html#predefined-implicit -definitions –

Смежные вопросы