Sound null safety dans Dart: une nouvelle façon d'écrire du code plus fiable
Le concept de sound null safety vous aide à prévenir les exceptions de pointeur nul et à écrire un code plus fiable.
Google a récemment publié la troisième version du langage Dart lors de sa conférence annuelle, la Google I/O. Il s'agit de la plus grande version de Dart à ce jour, et elle apporte trois changements majeurs parmi lesquels le 100 % sound null safety qui fait l'objet de cet article.
Si vous êtes un développeur Flutter, vous serez ravi d'apprendre que Dart 3 est entièrement compatible avec Flutter. Cela signifie que vous pouvez utiliser toutes les nouvelles fonctionnalités de Dart 3 dans vos applications Flutter.
Dart est un langage puissant et polyvalent utilisé pour développer une grande variété d'applications. Avec la sortie de Dart 3, Dart est désormais plus puissant, plus expressif et plus performant que jamais.
C’est parti!
Null safety, pour ceux qui ne savent pas
Pour l'équivalent français, la traduction littérale est la sécurité des nullités, ou encore la sécurité de la nullabilité. [Je fais de mon mieux pour traduire😉]
Je vous explique…
Pour commencer, la nullabilité est un concept informatique qui représente l’état d’une variable qui peut prendre la valeur null (null sans (e) chers descendants de Molière 🤗).
Généralement les variables sont censées contenir un certain type de valeurs, un entier peut donc contenir les valeurs -1, 0, 9… et une chaine de caractère peut contenir la valeur “Partage si c’est utile”, ainsi de suite.
Exemple:
var i = 49;
var message = “Partage si c’est utile”;
var couleur = Color(0xFFC603FC);
En d’autres termes, les déclarations ci-haut signifient que les variables i, message et couleur sont censées contenir des valeurs selon leurs types respectifs.
Mais la plupart des langages de programmation, Dart inclus, possède le concept de la valeur null, - variable sans aucune valeur.
Imaginez que vous ayez une variable couleurFavorite pour stocker la préférence de couleurs des vos utilisateurs:
var couleurFavorite = Color(0xFF000000);
Il est tout a fait possible que nous souhaitions lui affecter une valeur null, parcequ’il peut se faire qu’une personne ne possède tout simplement pas de couleur favorite, alors on aura le code suivant.
var couleurFavorite = null;
Des valeurs null, c’est bien de penser à cette possibilité, mais cela nous pose un sérieux problème.
Si une variable peut être d’un certain type (entier, chaîne de caractère...) ou null, alors il devient obligatoire, avant son utilisation, de vérifier si elle contient une valeur ou si elle est nulle.
Est-ce que cette couleur est une couleur ou cette couleur est null?
Est-ce que cette chaîne de caractère est une chaîne de caractère ou est-elle null?
Embarrassant n’est ce pas? De ne pas être sûr de ce que possède une variable…
Ceci ne vous rappelle pas l'expérience du chat de Schrödinger? 😅
Null ou non null? C’est difficile d’y penser tout le temps, et les développeurs ont tendance à introduire des erreurs de type "null" assez souvent. Ce type d'erreur, erreur de déréférencement nulle, peut être difficile à déboguer.
Vous devez savoir une chose, les erreurs de type null sont très mauvaises. Elles peuvent faire planter votre application, et c’est quelque chose que vos utilisateurs ne peuvent apprécier.
Si une application serveur tombe en panne, vous pouvez souvent la redémarrer sans que personne ne s'en aperçoive. Mais lorsqu'une application est entre les mains de vos utilisateur tombe en panne, sur le téléphone par exemple, celui-ci n'est pas content. Lorsque vos utilisateurs ne sont pas satisfaits, vous ne l'êtes pas non plus.
Null safety, on y arrive
C’est est une fonctionnalité du langage Dart qui permet d'éviter les exceptions de pointeur nul au moment de l'exécution de votre programme.
Pour ce faire, Dart se rassure que toutes les variables sont non nullables et des vérifications statiques sont effectuées pour s'assurer que les variables ne sont jamais assignées à des valeurs null.
Cela facilite grandement l'écriture d'un code fiable et permet d'éviter les plantages et autres erreurs.
Par exemple:
int age = 22;
La variable age est non-nullable, elle ne peut jamais être affectée d'une valeur null. La variable age est toujours un nombre et jamais une valeur null. Tous les types de variables sont non-nullables.
Dans Dart 2, le code suivant sera compilé et exécuté, mais il lèvera une exception de pointeur null au moment de l'exécution si vous essayez d'utiliser la variable age.
int age = null;
Mais dans Dart 3, les variables sont non nullables. Cela signifie que vous ne pouvez pas assigner null à une variable à moins que vous ne spécifiiez explicitement qu'elle est nullable. Par exemple, le dernier code ne sera même pas compilé dans Dart 3 et génère l'erreur suivante:
Error: variable age must be initialized with a non-null value
Que faire si malgré tout, on reçoit une valeur null?
Évidemment, tout ceci a été prévu, vous pouvez continuer d'utiliser les valeurs null, mais avec le null safety, vous devez être explicite.
Par exemple:
Color? couleurFavorite;
En ajoutant le point d’interrogation au type de la variable, nous disons à Dart que la variable couleurFavorite peut être une couleur ou null, on rend la variable nullable.
Le fait d'être explicite permet au langage de nous éviter certaines erreurs lors de l'exécution de notre programme.
Si vous essayez d’utiliser la variable couleurFavorite comme si c'était une couleur en oubliant la possibilité qu’elle peut-être null, Dart vous le fera savoir.
Dart est “sound” null safety
Le concept de null safety, Dart le partage avec plusieurs autres langages, par contre le sound null safety est souvent moins implémenté.
Un tableau comparatif:
Null Safety | Sound null safety | |
C# | ✅ | |
Dart | ✅ | ✅ |
Kotlin | ✅ | |
Swift | ✅ | ✅ |
TypeScript | ✅ |
Avec le sound null safety, lorsque Dart détermine qu’une valeur est non nullable, cette valeur est toujours non nullable. Ce qui diffère de plusieurs autres langages qui sont unsound null safety.
Sound null safety est une forme plus avancée de null safety qui fournit des garanties supplémentaires sur le comportement du code. Dans un programme solidement sécurisé, le compilateur peut garantir qu'aucune exception de pointeur null ne se produira lors de l'exécution, même si le programme est utilisé d'une manière que le programmeur n'avait pas prévue.
Ainsi, avec ce concept de sound null safety, Dart optimise votre code pour qu’il devienne non seulement sûr, mais le rend également rapide.
Cela implique qu'à chaque fois que vous déclarez une variable qui peut potentiellement contenir une valeur null, vous devez explicitement dire à Dart que cette variable peut être null.
Dans l'exemple ci-dessous, couleurFavorite est et devra toujours contenir une valeur non null.
Color couleurFavorite;
Et dans l'exemple suivant, couleurFavorite peut soit contenir une valeur ou être null.
Color? couleurFavorite;
Ceci ne s’applique pas seulement aux déclarations de variables, mais aussi:
Aux argument de fonctions
void changerCouleur(Color? couleur){
// …
}
Aux types de retour de fonctions
Color? obtenirCouleurFavorite(){
//…
}
Aux types génériques
List<Color?> couleursFavorites;
Et plus encore…
Vouloir accéder à une variable, alors qu’elle a comme valeur null peut faire crasher votre programme, alors comment éviter ces erreurs?
C'est simple, vérifier si une variable n’est pas null avant d’y accéder
Exemple:
void changerCouleur(Color? couleur){
if(couleur != null){
// Vous pouvez accéder à la variable couleur
}
}
Si vous assignez une variable non nullable à une variable nullable, c’est OK, comme dans l’exemple ci-dessous.
void changerCouleur(Color? couleur){
if(couleur != null){
// Vous pouvez accéder à la variable couleur
}
}
Color uneCouleur = Color(0xFFA99000);
changerCouleur(uneCouleur); ✅
La variable uneCouleur est toujours une couleur et n’est jamais null. Donc la fonction changerCouleur peut recevoir en parametre soit une couleur, soit un null.
Par contre, comme dans l’exemple suivant, passer une variable nullable en paramètre d’une fonction qui attend une variable non nullable pose un problème.
void changerCouleur(Color couleur){
// Vous pouvez accéder à la variable couleur
}
Color? uneCertaineCouleur = null;
changerCouleur(uneCertaineCouleur); ❌
Dans cet exemple, la fonction changerCouleur vous dit carrément qu’elle ne prend jamais de variables nullables.
Deux autres possibilités pour vérifier si une variable est null
La première consiste à utiliser des valeurs par défaut si vous savez que votre variable est null.
void changerCouleur(Color couleur){
// Vous pouvez accéder à la variable couleur
}
Color? uneCertaineCouleur = obtebirCouleur();
changerCouleur(uneCertaineCouleur ?? leBleu); ✅
La syntaxe avec les ?? permet de vérifier si la variable est null, si c’est le cas on passe une valeur par defaut.
La deuxième consite à forcer une variable nullable avec un point d’exclamation, si la variable est null, une exception sera levée.
void changerCouleur(Color couleur){
// Vous pouvez accéder à la variable couleur
}
Color? uneCertaineCouleur = obtebirCouleur();
changerCouleur(uneCertaineCouleur!); ✅
Vous devriez utiliser cette technique seulement si vous êtes sûr à 100% que votre variable n’est pas null.
Conclusion
Ce qui peut-être retenu, le sound null safety rend votre code sûr et rend son exécution plus rapide avec un minimum d’impact sur la manière dont vous l'écrivez.
Il permet d’améliorer les performances du code Dart en éliminant la nécessité de vérifier les valeurs null au moment de l'exécution et facilite le débogage du code en fournissant davantage d'informations sur la cause des erreurs.
Dart est suffisamment intelligent dans son analyse pour vous permettre de faire des choses sans trop d'éléments superflus mais ne vous permet pas d'introduire des bogues de référence nulle.
Sound null safety est une fonctionnalité puissante qui peut vous aider à écrire un code Dart plus sûr, plus fiable et plus performant. Si vous débutez avec Dart, je vous recommande d'activer la fonction sound null safety dès que possible.
Merci pour votre intérêt, et restez en mode null safety🦺.