Est-ce que toutes les variables devraient être const par défaut ?

Article original : Should every variable be const by default? | Belay the C++ (belaycpp.com)
Traductrice : Chloé Lourseyre

Un peu de terminologie

Dans le titre de l’article, j’utilise le mot const car const est un mot-clé que tous les développeurs C++ connaissent (enfin j’espère). Cela dit, le concept qui est adressé ici porte un nom plus générique, il s’agit de l’immuabilitéconst est un mot-clé utilise dans certains langages (comme le C++ ou le Javascript par exemple) mais la notion d’immuabilité existe aussi dans d’autres langages (qui parfois n’ont même pas de mot-clé équivalent à const, comme en Rust par exemple).

Ainsi, afin d’être inclusif, j’utiliserai les mots immuable et immuabilité à la place des mots constant et constance.

Nota bene : en C++ le mot-clé const ne représente pas exactement la notion d’immuabilité. Par exemple, vous pouvez utiliser le mot-clé const dans le prototype d’une fonction pour indiquer que vous n’allez pas le modifier, mais vous pouvez tout à fait passer une variable muable à cette fonction en guise de paramètre. Cela étant dit, cet article s’en réfère à const pour son caractère à rendre les données immuables, donc je vous saurais gré d’ignorer les cas où const ne s’en réfère pas à des données qui sont immuables de manière inhérente. C’est aussi une autre raison pour laquelle je préfère dire immuable et non pas constant.

Quelques très bonnes raisons de rendre vos variables immuables

Sécurité

Ce qu’on appelle la const-correctness (qui peut être maladroitement traduit en correction de constance, avec « correction » au sens de « qui est correct ») est une notion importante en C++ qui correspond au fait que si vous spécifiez qu’une variable est immuable, alors elle ne sera pas modifiée.

La const-correctness est atteinte lorsque vous utilisez le mot-clé const pour indiquer quelles variables ne doivent pas être modifiées. Ainsi, vous ne pourrez pas modifier par inadvertance des données qui n’ont pas à l’être et cela donne une indication sémantique aux autres développeurs et au compilateur.

Documentation

Ces cinq petits caractères en disent long. Si vous vous trouvez dans un code digne de confiance, la présence -ou l’absence- du mot-clé const donne des informations importantes sur les intentions derrière telle ou telle variable.

Optimisation

Le compilateur peut (et va) optimiser le code en fonction des directives d’immuabilité

En sachant si telle ou telle variable est immuable, le compilateur pourra faire des suppositions et prendre des raccourcis.

Si vous voulez en savoir plus à ce sujet je vous conseille le talk de J. Turner : Jason Turner: Practical Performance Practices – YouTube

Sources

Si vous n’êtes toujours pas convaincu(e) que l’immuabilité est utile (au bas mot), ou si vous êtes juste curieux(se), vous pouvez lire les articles suivants :

Y a-t-il des inconvénients à utiliser l’immuabilité dès que possible ?

Comme l’immuabilité est une restriction technique, il n’y a aucun inconvénient technique à l’utiliser.

Cependant, il peut y avoir des inconvénients plus subjectifs. Premièrement, cela augmente un peu la verbosité du code. Même s’il ne s’agit que de cinq caractères (qui dans la plupart des IDE prennent la même couleur que le type associé), certaines personnes peuvent trouver cela gênant. Il y a également une forme d’inertie qui peut apparaître : si à un moment donné vous avec besoin que la donnée soit muable, alors vous devrez aller chercher sa déclaration et la modifier. Certains considèrent cela comme une mesure de sécurité, d’autres comme un inconvénient.

Est-ce que ces arguments sont suffisants pour ne pas utiliser l’immutabilité dès qu’on le peut ? C’est à vous de juger, mais en mon humble avis, je ne pense pas.

Et les autres langages ?

D’autres langages ont effectivement rendu les variables immuables par défaut.

C’est le cas du Rust. En Rust, vous n’avez pas d’équivalent du mot-clé const, toutes les variables sont immuables par défaut. Au contraire, vous avez le mot-clé mut (pour mutable, la traduction anglaise de muable) que vous devez apposer devant chaque variable muable.

Par exemple, le code suivant ne compile pas en Rust :

fn main() {
    let foo = 2;
    println!("Foo: {}", foo);
    foo += 40; // error[E0384]: cannot assign twice to immutable variable `foo`
    println!("Foo: {}", foo);
}

Mais il faut plutôt écrire ceci :

fn main() {
    let mut foo = 2;
    println!("Foo: {}", foo);
    foo += 40;
    println!("Foo: {}", foo);
}

La raison mentionnée dans le manuel Rust est la suivante (je traduis) : « C’est un des nombreux coups de pouce que le Rust vous donne pour écrire du code qui tire profit de la sécurité […] que le langage a à offrir. »

Rust est un langage moderne qui vise à produire du code sécurisé tout en étant performant. Dans cette optique je suis d’accord avec le choix qu’il a fait de rendre les variables immuables par défaut pour la sécurité que cela apporte.

Est-il raisonnable de changer le standard pour rendre toutes les variables immuables par défaut ?

Si un jour fatidique, le C++ committee décide de rendre toutes les variables immuables par défaut… personne ne migrera vers cette nouvelle version du standard.

La rétro-compatibilité est importante pour adoucir les migrations. Il y a des exemples historiques de suppression de fonctionnalité du standard, mais à chaque fois il y avait une très bonne raison pour cela (la plupart du temps étant que cette fonctionnalité était obsolète depuis des lustres).

On ne peut pas sérieusement penser à enlever const du standard et le remplacer par un mut juste pour égard à ce qui est, en définitive, du sucre syntaxique.

Que faire alors ?

Pour ma part, j’utilise le mot-clé const systématiquement sans réfléchir, chaque fois que je déclare une variable. Je ne l’enlève que lorsque j’écris une instruction qui requiert effectivement que la variable soit muable (ou quand le compilateur me crie que j’essaye de modifier une variable constante). C’est un peu brut, mais selon moi c’est le meilleur moyen d’acquérir le bon réflexe de mettre const dès que l’on peut.

Bien sûr, vous pensez sans doute qu’on peut être plus malin et en essayant de prévoir si la variable sera mutable dès sa déclaration, mais je peux garantir que vous ne serez pas 100% fiables et vous laisserez passer des opportunités de rendre des données immuables (du moins, tant que vous n’aurez pas pris cette bonne habitude).

Voici donc mon conseil : jusqu’à ce que vous ayez le réflexe de mettre des const partout où vous les pouvez, utilisez const systématiquement et pour toutes les variables. Au pire vous aurez quelques erreurs de compilation facile à corriger, au mieux vous attraperez une bonne habitude.

Et quid de constexpr ?

constexpr est un mot-clé qui permet d’indiquer qu’une expression peut être évaluée au moment de la compilation. Le but est d’essayer de gagner du temps d’exécution en faisant un plus gros travail à la compilation.

En un sens, c’est une immutabilité plus forte que const. Tout ce que j’ai dit dans cet article peut s’appliquer à constexpr : utilisez-le dès que c’est possible.

Cependant, contrairement à const, je ne vous conseille pas d’être spécialement trop zélé(e)s avec constexpr.
Il est plus rare de pouvoir l’utiliser et les cas d’utilisation sont un peu plus évidents que son homologue. Mais gardez bien en tête d’utiliser constexpr dès que possible.

Merci de votre attention et à la semaine prochaine !

Article original : Should every variable be const by default? | Belay the C++ (belaycpp.com)
Traductrice : Chloé Lourseyre

Laisser un commentaire