ProgrammationDéveloppeur Backend

Qu'est-ce que des paramètres reified en ligne (reified generics) en Kotlin, quand et pourquoi les utiliser, quelles sont les limitations et quels sont des exemples de leur application ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Contexte de la question :

Dans la JVM, au moment de l'exécution, il n'y a pas d'informations sur les paramètres de génération (type erasure). Kotlin a proposé un mécanisme de paramètres de type générique reified pour les fonctions en ligne, afin de réaliser l'accès à des informations de type T pendant l'exécution sans les contraintes de passer Class<T>. C'est l'un des outils les plus puissants du langage Kotlin.

Problème :

Il faut écrire une fonction qui prend une certaine valeur de type T (générique) et exécuter différentes actions en fonction du type du paramètre, sans passer explicitement java.lang.Class et sans utiliser la réflexion à la manière de Java. L'effritement classique des types ne permet pas de déterminer le type T pendant l'exécution.

Solution :

En Kotlin, il est possible de déclarer des paramètres génériques avec le modificateur reified pour les fonctions en ligne, ce qui permet "d'immobiliser" le type T à l'intérieur du corps de la fonction, de travailler avec lui comme avec un type normal, de réaliser des vérifications de type et de créer des instances via la réflexion.

Exemple de code :

inline fun <reified T> isOfType(value: Any): Boolean { return value is T } isOfType<String>(123) // false isOfType<Int>(123) // true

Caractéristiques clés :

  • Accès au type T à l'intérieur de la fonction lors de l'exécution
  • Possibilité d'effectuer des opérations comme value is T, T::class, T::class.java
  • Fonctionne uniquement pour les fonctions en ligne

Questions trompeuses.

Peut-on utiliser reified en dehors des fonctions en ligne ?

Non ! Seules les fonctions en ligne (et les propriétés en ligne paresseuses) peuvent avoir des paramètres génériques reified. La raison est que le code est substitué à l'endroit de l'appel, c'est la seule manière de "remplacer" un type concret à la place de T.

Exemple de code :

// Erreur de compilation : fun <reified T> errorFun() { } // Variante correcte : inline fun <reified T> okFun() { }

Peut-on obtenir Class<T> à l'intérieur d'une fonction reified en ligne ?

Oui ! Il suffit d'écrire T::class.java ou T::class. C'est extrêmement pratique pour écrire des fabriques génériques, des parseurs et travailler avec l'API de réflexion.

Exemple de code :

inline fun <reified T> printType() { println(T::class.java) } printType<String>() // class java.lang.String

Peut-on créer des instances de type T via un constructeur dans une fonction reified ?

Partiellement. Il est possible d'utiliser la réflexion, mais on ne peut pas faire directement new T() comme en C++ ou C# :

inline fun <reified T : Any> makeInstance(): T? { return T::class.constructors.firstOrNull()?.call() }

Mais cette approche nécessite que T possède un constructeur sans paramètres.

Erreurs typiques et anti-patrons

  • Réutilisation de reified trop souvent au lieu de passer explicitement le type (par exemple, partout où Class<T> est simplement requis)
  • Utilisation de reified en dehors des fonctions en ligne
  • Attendre qu'il soit toujours possible d'instancier T sans fournir le constructeur approprié

Exemple de la vie réelle

Cas négatif

Fonction avec reified, appelant une opération de réflexion lourde dans le code :

inline fun <reified T> foo(): T? = T::class.constructors.firstOrNull()?.call()

Avantages :

  • Universel, pratique pour les tests

Inconvénients :

  • Lent
  • Pas de contrôle sur les erreurs du constructeur, difficile à débugger

Cas positif

Utilisation de reified pour une vérification de type universelle ou un safeCast :

inline fun <reified T> safeCast(value: Any?): T? = value as? T

Avantages :

  • Concis
  • Sûr (as ?)
  • Pas de surcharge de performance

Inconvénients :

  • Pris en charge uniquement dans les fonctions en ligne