почему в асинхронной подписи с эффектом cat используется Either [Throwable, A], а не Try [A]? - PullRequest
2 голосов
/ 25 сентября 2019

Давным-давно мы долго спорили в нашей команде об использовании Try[A] против Either[Throwable, A], и в итоге мы выбрали Try[A], потому что они семантически одинаковы, когда левая сторона Either равна Throwable.В то время я искал кодовую базу, где используется Either[Throwable, A], но я не смог ее найти.

Но сегодня, когда смотрел выступление Фабио Лабеллы о Как работают волокна?Взгляд под капотом , следующая подпись поразила меня


    def async[A](k: (Either[Throwable, A] => Unit) => Unit): F[A]

Так что мой вопрос: есть ли конкретная причина для использования Either[Throwable, A] вместо Try[A]?Какой из них рекомендуется?

Ответы [ 2 ]

1 голос
/ 25 сентября 2019

Я не уверен, что семантика полностью изоморфна между Try[A] и Either[Throwable, A].Например, мы можем изменить смещение Either

val e: Either[Throwable, Int] = Left(new Exception("boom"))
for (s <- e.left) yield s.getMessage.length
res5: scala.util.Either[Int,Int] = Left(4)

или поменять местами

e.swap
res6: scala.util.Either[Int,Throwable] = Right(java.lang.Exception: boom)

Рассмотрим некоторый необычный сценарий, где мы считаем Throwable s фактически ожидаемый результат и, следовательно, хотел бы их на стороне Right.Возможно, мы создаем некую чисто функциональную библиотеку тестирования, где мы хотим предоставить API для утверждения об исключениях.Можно представить кодирование этой семантики как Either[A, Throwable].

Другим потенциальным преимуществом Either над Try могут быть кошки, предоставляющие для него больше методов расширения.Например, рассмотрим все вкусности в import cats.syntax.either._, пока я не знаю о подобных для Try.Скажем, мы хотим накапливать все ошибки в списке вместо короткого замыкания, тогда мы можем просто traverse(_.toValidatedNec) вот так

import cats.syntax.either._
import cats.instances.list._
import cats.syntax.traverse._

val l: List[Either[Throwable, Int]] = List(Right(1), Right(2), Left(new RuntimeException("boom")), Right(3), Left(new RuntimeException("crash")))
l.traverse(_.toValidatedNec)
res0: cats.data.ValidatedNec[Throwable,List[Int]] = Invalid(Chain(java.lang.RuntimeException: boom, java.lang.RuntimeException: crash))

Чтобы добиться аналогичного с Try Я думаю, нам придется работать усерднее.

0 голосов
/ 25 сентября 2019

Снятие ответов с на этот вопрос , вот список отличий:

  • Либо не означает успех и неудачу, это просто контейнер для А илиa B
  • Использование Попробуйте четко определить потенциальный сбой в вычислении, причем этот отказ представлен в виде исключения
  • Что приятно в Try [X], так это то, что вы можете связать с ним дальнейшие операции, если это действительно успех, который они выполнят, если это был отказ, они не будут
  • Try имеет множество других полезных методов, и, конечно, его метод применения компаньона, который делает его очень удобным для предполагаемогоиспользование - обработка исключений.
  • Любой может быть использован для указания описания ошибки, которое может быть показано клиенту.Try - оборачивает исключение трассировкой стека
  • Хорошими кандидатами на Try являются методы, которые могут вызвать исключение, или методы, отправляющие запрос во внешние системы
...