Kotlin Result DSL
Эдит: вариант для чтения на мобилках
И кстати в догонку про обработку ошибок.
Я в своё время прям сильно впечатлился Rust-овским try! (Который уже оказывается стал ?-оператором)
И недавно запилил драфт похожей штуки для Котлина:
Это аналог вот такому коду:
Совсем однострочник сделать не получается, т.к. в Котлине нет полноценных макросов, а для того чтобы этот приём абстрагировать в функцию, в ней надо сделать ретарн из произвольной вызывающей функции с неизвестным типом возврата.
Но спрашивается зачем всё это?
В Котлине возврат того или иного Result - это единственный способ явно показать вызывающему коду, что функция может ошибиться. А очевидность вообще и очевидность мест где что-то может пойти не так - это основа эргономичного кода.
Но если это делать наивно, то получается код как из втрого примера.
Вообще Result-ы как правило являются монадами и с ними можно работать так:
И так получается даже короче. Но в Котлине нет спец синтаксиса для монад и поэтому они не масштабируются.
Например, если надо выполнить ИО-операцию на базе результата первых двух (и только в случае их успеха), то будет вот такой адок:
С моим же DSL-ем, всё будет прилично:
Полный код DSLя
#error_handlin@ergonomic_code #kotlin@ergonomic_code #posts@ergonomic_code #ergo_approach@ergonomic_code
Эдит: вариант для чтения на мобилках
И кстати в догонку про обработку ошибок.
Я в своё время прям сильно впечатлился Rust-овским try! (Который уже оказывается стал ?-оператором)
И недавно запилил драфт похожей штуки для Котлина:
fun testReturn(): WorkflowResult<Int, Throwable> {
val int = doIo()
.onError { return it }
return Result(int + 1)
}
Это аналог вот такому коду:
fun testLong(): WorkflowResult<Int, Throwable> {
val res = doIo()
if (res is Error) {
return res
}
val int = (res as Success).result
return Result(int + 1)
}
Совсем однострочник сделать не получается, т.к. в Котлине нет полноценных макросов, а для того чтобы этот приём абстрагировать в функцию, в ней надо сделать ретарн из произвольной вызывающей функции с неизвестным типом возврата.
Но спрашивается зачем всё это?
В Котлине возврат того или иного Result - это единственный способ явно показать вызывающему коду, что функция может ошибиться. А очевидность вообще и очевидность мест где что-то может пойти не так - это основа эргономичного кода.
Но если это делать наивно, то получается код как из втрого примера.
Вообще Result-ы как правило являются монадами и с ними можно работать так:
val res = doIo()
return res.map { it + 1}
И так получается даже короче. Но в Котлине нет спец синтаксиса для монад и поэтому они не масштабируются.
Например, если надо выполнить ИО-операцию на базе результата первых двух (и только в случае их успеха), то будет вот такой адок:
fun testCompositeM(): Optional<Int> {
val first = mIo()
val second = first.flatMap { mIo2(it) }
return first.flatMap { firstVal ->
second.flatMap { secondVal ->
mIo2(firstVal + secondVal)
}
}
}
С моим же DSL-ем, всё будет прилично:
fun testComposite(): WorkflowResult<Int, Throwable> {
val first = doIo().onError { return it }
val second = doIo2(first).onError { return it }
return doIo2(first + second)
}
Полный код DSLя
#error_handlin@ergonomic_code #kotlin@ergonomic_code #posts@ergonomic_code #ergo_approach@ergonomic_code
Telegraph
Kotlin Result DSL
И кстати в догонку про обработку ошибок. Я в своё время прям сильно впечатлился Rust-овским try! (Который уже оказывается стал ?-оператором) И недавно запилил драфт похожей для штуки для Котлина: