# 🇫🇷 Type Result en Kotlin
# Origines de cet article
Il y a quelques années, je me suis retrouvé à faire un onboarding pour un nouveau job à San Fransisco. Mon côté 🐻 et mon niveau en 🇬🇧 de l'époque ont fait que j'ai passé pas mal de temps à l'hôtel quand je ne partais pas pour de longues marches. J'en ai profité pour une n-ième tentative dans ma compréhension de la programmation fonctionnelle. Et c'est à ce moment que j'ai découvert une nouvelle méthode de gestion des erreurs. Et ce fut l'occasion de remettre le nez dans Scala (avec plus de succès).
Mes types préférés furent Try
, Success
, Failure
. Une instance de Try
sera soit un Success
(contenant une valeur), soit un Failure
(contenant un message d'erreur).
Du coup, mon nouveau principe de gestion des erreurs devint le suivant: une fonction retourne un Try
et à chaque appel de ma fonction je suis "obligé" de tester si le retour est un Success
ou un Failure
si je veux avoir la valeur de mon retour(mon resultat, donc la valeur "contenue" par mon Try
).
Voici un exemple tiré de FUNCTIONAL ERROR HANDLING IN SCALA (opens new window):
import scala.util.{Try,Success,Failure}
def toInt(s: String): Try[Int] = Try {
Integer.parseInt(s.trim)
}
toInt(x) match {
case Success(i) => println(i)
case Failure(s) => println(s"Failed. Reason: $s")
}
Je trouve que c'est plutôt expressif et à l'usage cela apporte une meilleure lisibilité de mon code.
# Scala c'est top, mais Kotlin est apparu ... Et aussi Arrow
Je ne me souviens pas de à quel moment exact j'ai entendu parler de Kotlin, mais c'était en 2012 Faites vos classes en Kotlin (opens new window). Ma 1ère conclusion fut "ce nouveau langage me plaît beaucoup, une touche de Java, une touche de Javascript, une touche de C#". 🖐️ J'aurais du ajouter "une touche de Scala", mais mon "voyage fonctionnel" n'a réellement commencé qu'en Avril 2016 (à San Fransisco 😉).
En Décembre 2018, j'écrivais 🇬🇧 Some reasons why I build my server stack with Vert-x, Kotlin, and Arrow.kt (opens new window). J'avais découvert lors d'une conférence Arrow.kt (opens new window)
Et ce qui m'a le plus plus c'était que Arrow fournissait un Try
🎉:
fun giveMeSomething(): Try<Any> {
return Try {
when((0..2).shuffled().first()) {
0 -> throw Exception("🤭 Oups! I did it again")
1 -> 42
else -> 666
}
}
}
router.get("/oups") { context ->
giveMeSomething().let {
when(it) {
is Failure -> context.json(json { obj("message" to it.exception.message) })
is Success -> context.json(json { obj("number" to it.value) })
}
}
}
J'étais heureux 😆
# Mais ... 😢
Mais un jour, tristesse, en bootstrapant un nouveau projet, je découvre en parcourant la documentation, que Try
est deprecated: https://arrow-kt.io/docs/0.10/apidocs/arrow-core-data/arrow.core/-try/index.html#try (opens new window). 😢😠😭
# Mais ... 🎉
Mais en cherchant un peu je découvre qu'il existe un type Result
en Kotlin 😃. Sauvé! Alors pas tout à fait, car on ne peut pas utiliser Return
comme un type de retour 🙀. Don't panic, il est possible d'activer un flag pour pouvoir l'utiliser pleinement (gardez à l'esprit que le "fonctionnement" de Result
dans le futur peut être amené à changer).
# Si vous utilisez Gradle
Activez le flag (1️⃣) de cette manière dans build.gradle.kts
:
tasks.withType<KotlinCompile>() {
kotlinOptions.jvmTarget = "11"
kotlinOptions.freeCompilerArgs = listOf("-Xallow-result-return-type") // 1️⃣ le flag c'est ici
}
# Si vous utilisez Maven
Activez le flag (1️⃣) de cette manière dans pom.xml
:
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<jvmTarget>11</jvmTarget>
<args>
<!-- 1️⃣ le flag c'est ici -->
<arg>-Xallow-result-return-type</arg>
</args>
</configuration>
# Et maintenant 🍾
Maintenant vous pouvez écrire ceci:
fun divide(a: Int, b: Int): Result<Int> {
return try {
Result.success(a / b)
} catch (exception: Exception) {
Result.failure(exception)
}
}
Et l'utiliser comme cela:
divide(42, 0).let {
when {
it.isFailure -> {
println("😡 ${it.exceptionOrNull()?.message}")
}
it.isSuccess -> {
println("🙂 result=${it.getOrDefault(0)}")
}
}
}
ou aussi:
divide(42, 0)
.onFailure { failure -> println("😡 ${failure.message}") }
.onSuccess { result -> println("🙂 result=${result}") }
J'espère réellement que cela deviendra un standard en Kotlin car c'est réellement pratique et agréable à utiliser. Bien sûr il est possible d'écrire sa propre implémentation de Result
. Mais je suis persuadé que c'est beaucoup mieux si c'est le langage qui supporte cette fonctionnalité plutôt qu'un framework.
Bon week end 😘
Last Articles
- 🇫🇷 Type Result en Kotlin | 2020-10-31 | Kotlin
- 🇫🇷 Type Result en Kotlin | 2020-10-31 | Kotlin
- 🇬🇧 Every GitLab Page deserves a real CI/CD | 2020-07-23 | GitLab CI
- 🇫🇷 Lit-Element, commencer doucement | 2020-07-20 | WebComponent
- 🇬🇧 Build quickly and host easily your Docker images with GitLab and GitLab CI | 2020-06-02 | GitLab CI
- 🇬🇧 Deploy quickly on Clever Cloud with GitLab CI | 2020-05-31 | GitLab CI
- 🇫🇷 Borg Collective, mes jouets pour apprendre Knative | 2020-05-30 | Knative
- 🇬🇧 Borg Collective, Toys to learn Knative | 2020-05-30 | Knative
- 🇫🇷 M5Stack, une petit device IOT bien sympathique, programmable en Python | 2020-05-09 | IOT
- 🇫🇷 Knative, l'outil qui rend Kubernetes sympathique | 2020-05-02 | kubernetes