Комментарии 10
Преимущества предлагаемого решения так и не понял. Классический вариант с try/catch
примерно одинаково выглядит и работает во всех императивных языках, от C++/Java/C# до PHP/JS/Ruby, поэтому большинству будет понятен интуитивно. Здесь же появляются — Try
, monad
, binding
, pure
, recover
, recoverWith
, flatMap
, bind
, и в другом языке\другой библиотеке они будут называться по-другому.
Еще одна проблема — иллюзия безопасности. Когда вы где-то обрабатываете ошибки явно создается впечатление, что в остальных строках ошибка впринципе не может возникнуть, однако язык/рантайм таких гарантий не дает. В итоге, если у вас есть какие-то требования к стабильности, то вам все равно придется на некотором уровне обернуть весь код в try/catch
— чтобы, например, при непредвиденной ошибке при обработке одного запроса упал только этот запрос, а не весь сервис.
fun makeRequest(request: String): List<Any>? = try {
listOf()
} catch (e: Exception) {
null
}
fun main(args: Array<String>) {
makeRequest("body")?.let {
it.map { it.toString() }
} ?: emptyList()
}
тоже самое, только из коробки, без доп-оберток и матчинг эксепшена по типу
тоже самое, только из коробки
Нет, не тоже самое. Вы просто проглотили исключение. В Try же exception есть и в конце статьи написано как оно может быть обработано.
Профита не видно
В статье не самым лучшим образом отражено, а вообще это нужно для того, чтобы можно было делать цепочку из монад с дальнейшей обработкой.
Наверное, главная цель статьи — это, чтобы на хабре Arrow хотя бы упоминался (не нашел по нему статей). А чтобы это упоминание не отпугивало обилием информации (а библиотека ведь очень богатая) — статья должна была быть поверхностной. Поэтому абзац про цепочки монад был написан — и вырезан перед отправкой.
Нет, не тоже самое. Вы просто проглотили исключение. В Try же exception есть и в конце статьи написано как оно может быть обработано.ну да, если его надо обработать выше, надо просто этот же код написать выше, в чем тут проблема-то? и `try` надо только в одном месте написать.
цепочку из монад с дальнейшей обработкой
вызов метдов с `try-catch` это разве не цепочка с обработкой? в чем профит-то?
Усложнение всё-таки должно быть чем-то оправдано, того, что я увидел в статье явно не хватает, чтобы взять это в использование в каких-то реальных кейзах, которые я использую. Я использую цепочки обработки для коллекций, например, там понятно, что мы получаем, декларативность, скрываем не относящийся к происходящему и повторяющийся код, а тут что? Заменили один механизм из коробки на другой из библиотеки, при этом декларативности особенной или переиспользования или понятности не получили, только усложнение и дополнительные зависимости.
вызов метдов с `try-catch` это разве не цепочка с обработкой? в чем профит-то?
Ну принцип тот же, что и в Stream API — это практически цепочка монад. Удобно будет например внутрь map или filter засовывать обработку try-catch?
inline fun <R> tryOrNull(block: () -> R?): R? = try {
block()
} catch (e: Exception) {
null
}
fun aaa() {
listOf(1, 2, 3).mapNotNull { tryOrNull { it / 0 } }
}
Сначала придумывают checked exceptions в Java.
Для того, чтобы
любой кто будет читать этот код после тебя (а такие скорее всего будут) уже по сигнатуре сможет понять, что исполнение кода может привести к ошибке — и написать код её обработки. Тем более, что компайлер заругается, если это не будет сделано.
Потом говорят — не, не хотим возиться и всюду загрязнять сигнатуры методов, и перестают их использовать и вообще не делают такое в Котлине и Скале.
Потом говорят — как же так? Мы же не знаем какой может тут вылететь эксепшн!
Давайте сделаем Try в Котлине и скале, чтобы
любой кто будет читать этот код после тебя (а такие скорее всего будут) уже по сигнатуре сможет понять, что исполнение кода может привести к ошибке — и написать код её обработки. Тем более, что компайлер заругается, если это не будет сделано.
Функциональная обработка ошибок в Kotlin с помощью Arrow