Constant (programmation informatique) - Constant (computer programming)

En programmation informatique , une constante est une valeur qui ne doit pas être modifiée par le programme pendant l'exécution normale, c'est-à-dire que la valeur est constante . Lorsqu'elle est associée à un identifiant, une constante est dite « nommée », bien que les termes « constante » et « constante nommée » soient souvent utilisés de manière interchangeable. Cela contraste avec une variable , qui est un identifiant avec une valeur qui peut être modifiée pendant l'exécution normale, c'est-à-dire que la valeur est variable. Les constantes sont utiles à la fois pour les programmeurs et les compilateurs : pour les programmeurs, elles constituent une forme de code auto-documenté et permettent de raisonner sur l' exactitude , tandis que pour les compilateurs, elles autorisent des vérifications à la compilation et à l' exécution qui vérifient que les hypothèses de constance ne sont pas violées et permettent ou simplifier certaines optimisations du compilateur .

Il existe diverses réalisations spécifiques de la notion générale de constante, avec des distinctions subtiles qui sont souvent négligées. Les plus importantes sont : les constantes de compilation (à valeur statique), les constantes d'exécution (à valeur dynamique), les objets immuables et les types de constante ( const ).

Des exemples typiques de constantes de compilation incluent des constantes mathématiques, des valeurs de normes (ici unité de transmission maximale ) ou des valeurs de configuration interne (ici caractères par ligne ), telles que ces exemples C :

const float PI = 3.1415927;  // maximal single float precision
const unsigned int MTU = 1500;  // Ethernet v2, RFC 894
const unsigned int COLUMNS = 80;

Des exemples typiques de constantes d'exécution sont des valeurs calculées en fonction des entrées d'une fonction, comme cet exemple C++ :

void f(std::string s) {
  const size_t l = s.length();
  // ...
}

Utilisation

Certains langages de programmation font une distinction syntaxique explicite entre les symboles constants et variables, par exemple en considérant l' affectation à une constante comme une erreur de syntaxe, tandis que dans d'autres langages, ils sont considérés comme syntaxiquement identiques (tous deux simplement un identifiant), et la différence de traitement est sémantique (l'affectation à un identifiant est syntaxiquement valide, mais si l'identifiant est une constante, il est sémantiquement invalide).

Une valeur constante est définie une fois et peut être référencée plusieurs fois tout au long d'un programme. L'utilisation d'une constante au lieu de spécifier la même valeur plusieurs fois peut simplifier la maintenance du code (comme dans ne vous répétez pas ) et peut être auto-documentée en fournissant un nom significatif pour une valeur, par exemple, PIau lieu de 3.1415926.

Comparaison avec les littéraux et les macros

Il existe plusieurs manières principales d'exprimer une valeur de données qui ne change pas pendant l'exécution du programme et qui sont cohérentes dans une grande variété de langages de programmation. Une méthode très basique consiste simplement à écrire un nombre littéral , un caractère ou une chaîne dans le code du programme, ce qui est simple en C, C++ et langages similaires.

En langage assembleur, les nombres littéraux et les caractères sont effectués à l'aide des instructions "mode immédiat" disponibles sur la plupart des microprocesseurs. Le nom "immédiat" vient du fait que les valeurs sont disponibles immédiatement à partir du flux d'instructions , par opposition à leur chargement indirect en recherchant une adresse mémoire. D'autre part, les valeurs plus longues que la longueur de mot du microprocesseur, telles que les chaînes et les tableaux, sont traitées indirectement et les assembleurs fournissent généralement une pseudo-opération "données" pour intégrer ces tables de données dans un programme.

Une autre façon est de définir une macro symbolique . De nombreux langages de programmation de haut niveau et de nombreux assembleurs offrent une fonction macro où le programmeur peut définir, généralement au début d'un fichier source ou dans un fichier de définition séparé, des noms pour différentes valeurs. Un préprocesseur remplace ensuite ces noms par les valeurs appropriées avant la compilation, ce qui donne quelque chose de fonctionnellement identique à l'utilisation de littéraux, avec les avantages de vitesse du mode immédiat. Parce qu'il peut être difficile de maintenir un code où toutes les valeurs sont écrites littéralement, si une valeur est utilisée de manière répétitive ou non évidente, cela est souvent fait comme une macro.

Une troisième façon consiste à déclarer et à définir une variable comme étant « constante ». Une variable globale ou une variable statique peut être déclarée (ou un symbole défini dans l'assembly) avec un qualificateur de mot-clé tel que const, constant, ou final, ce qui signifie que sa valeur sera définie au moment de la compilation et ne devrait pas être modifiable au moment de l'exécution. Les compilateurs placent généralement des constantes statiques dans la section texte d'un fichier objet avec le code lui-même, par opposition à la section de données où les données initialisées non const sont conservées. Certains compilateurs peuvent produire une section spécifiquement dédiée aux constantes. La protection de la mémoire peut être appliquée à cette zone pour empêcher l'écrasement de telles constantes par des pointeurs errants.

Ces constantes diffèrent des littéraux de plusieurs manières. Les compilateurs placent généralement une constante dans un seul emplacement de mémoire identifié par un symbole, plutôt que de la répartir dans l'exécutable comme avec une macro. Bien que cela exclue les avantages de vitesse du mode immédiat, il existe des avantages en termes d'efficacité de la mémoire et les débogueurs peuvent travailler avec ces constantes au moment de l'exécution. De plus, alors que les macros peuvent être redéfinies accidentellement par des fichiers d'en-tête conflictuels en C et C++, des constantes conflictuelles sont détectées au moment de la compilation.

Selon la langue, les constantes peuvent être non typées ou typées. En C et C++, les macros fournissent le premier, tandis que constle second fournit :

#define PI 3.1415926535

const float pi2 = 3.1415926535;

tandis que dans Ada, il existe des types numériques universels qui peuvent être utilisés, si vous le souhaitez :

pi : constant := 3.1415926535;

pi2 : constant float := 3.1415926535;

la variante non typée étant implicitement convertie dans le type approprié à chaque utilisation.

Constantes à valeur dynamique

Outre les constantes statiques décrites ci-dessus, de nombreux langages procéduraux tels que Ada et C++ étendent le concept de constance vers des variables globales créées au moment de l'initialisation, des variables locales automatiquement créées lors de l'exécution sur la pile ou dans des registres, à la mémoire allouée dynamiquement qui est accessible par pointeur et aux listes de paramètres dans les en-têtes de fonction.

Les constantes à valeur dynamique ne désignent pas une variable comme résidant dans une région spécifique de la mémoire, et les valeurs ne sont pas définies au moment de la compilation. Dans du code C++ tel que

float func(const float ANYTHING) {
    const float XYZ = someGlobalVariable*someOtherFunction(ANYTHING);
    ...
}

l'expression à laquelle la constante est initialisée ne sont pas elles-mêmes constantes. L'utilisation de la constance n'est pas nécessaire ici pour la légalité du programme ou l'exactitude sémantique, mais présente trois avantages :

  1. Il est clair pour le lecteur que l'objet ne sera plus modifié, une fois défini
  2. Les tentatives de modifier la valeur de l'objet (par des programmeurs ultérieurs qui ne comprennent pas complètement la logique du programme) seront rejetées par le compilateur
  3. Le compilateur peut être en mesure d'effectuer des optimisations de code sachant que la valeur de l'objet ne changera pas une fois créé.

Les constantes à valeur dynamique ont été créées en tant que caractéristique du langage avec ALGOL 68 . Des études sur le code Ada et C++ ont montré que les constantes à valeur dynamique sont rarement utilisées, généralement pour 1% ou moins des objets, alors qu'elles pourraient être utilisées beaucoup plus, car environ 40 à 50% des objets locaux non-classe sont en fait invariants. une fois créé. D'un autre côté, ces "variables immuables" ont tendance à être la valeur par défaut dans les langages fonctionnels car elles favorisent les styles de programmation sans effet secondaire (par exemple, la récursivité) ou rendent la plupart des déclarations immuables par défaut, comme ML . Les langages purement fonctionnels interdisent même totalement les effets secondaires.

La constante est souvent utilisée dans les déclarations de fonctions, comme une promesse que lorsqu'un objet est passé par référence, la fonction appelée ne le changera pas. Selon la syntaxe, un pointeur ou l'objet pointé peut être constant, mais normalement ce dernier est souhaité. Surtout en C++ et C, la discipline consistant à s'assurer que les structures de données appropriées sont constantes tout au long du programme est appelée const-correctness .

Paramètres de fonction constants

En C/C++, il est possible de déclarer le paramètre d'une fonction ou d'une méthode comme constante. C'est une garantie que ce paramètre ne peut pas être modifié après la première affectation (par inadvertance). Si le paramètre est de type prédéfini (intégré), il est appelé par valeur et ne peut pas être modifié. S'il s'agit d'un type défini par l'utilisateur, la variable est l'adresse du pointeur, qui ne peut pas non plus être modifiée. Cependant, le contenu de l'objet peut être modifié sans limites. Déclarer des paramètres en tant que constantes peut être un moyen de signaler que cette valeur ne doit pas être modifiée, mais le programmeur doit garder à l'esprit que les vérifications concernant la modification d'un objet ne peuvent pas être effectuées par le compilateur.

Outre cette fonctionnalité, il est également possible en C++ de déclarer une fonction ou une méthode en tant que const. Cela empêche de telles fonctions ou méthodes de modifier autre chose que des variables locales.

En C#, le mot-clé constexiste, mais n'a pas le même effet pour les paramètres de fonction, comme c'est le cas en C/C++. Il existe cependant un moyen de « remuer » le compilateur pour effectuer la vérification, bien que ce soit un peu délicat.

Pour obtenir le même effet, d'abord, deux interfaces sont définies

public interface IReadable
{
    IValueInterface aValue { get; }
}

public interface IWritable : IReadable
{
    IValueInterface aValue { set; }
}

public class AnObject : IWritable
{
    private ConcreteValue _aValue;

    public IValueInterface aValue
    {
        get { return _aValue; }
        set { _aValue = value as ConcreteValue; }
    }
}

Ensuite, les méthodes définies sélectionnent la bonne interface avec des capacités de lecture seule ou de lecture/écriture :

public void doSomething(IReadable aVariable)
{
    // Cannot modify aVariable!
}

public void doSomethingElse(IWritable aVariable)
{
    // Can modify aVariable, so be careful!
}

Constantes orientées objet

Une structure de données ou un objet constant est appelé " immuable " dans le langage orienté objet. Un objet immuable confère certains avantages dans la conception du programme. Par exemple, il peut être "copié" simplement en copiant son pointeur ou sa référence, évitant une opération de copie longue et économisant de la mémoire.

Les langages orientés objet tels que C++ étendent encore plus la constante. Les membres individuels d'une structure ou d'une classe peuvent être rendus const même si la classe ne l'est pas. Inversement, le mutablemot - clé permet de modifier un membre de classe même si un objet a été instancié en tant que const.

Même les fonctions peuvent être const en C++. La signification ici est que seule une fonction const peut être appelée pour un objet instancié comme const ; une fonction const ne modifie aucune donnée non modifiable.

C# a à la fois un constet un readonlyqualificateur ; son const est uniquement pour les constantes de compilation, tandis que readonly peut être utilisé dans les constructeurs et autres applications d'exécution.

Java

Java a un qualificateur appelé finalqui empêche de changer une référence et s'assure qu'il ne pointera jamais vers un objet différent. Cela n'empêche pas les modifications de l'objet référencé lui-même. Java finalest fondamentalement équivalent à un const pointeur en C++. Il ne fournit pas les autres fonctionnalités de const.

En Java , le qualificateur finalindique que le membre de données ou la variable affecté n'est pas assignable, comme ci-dessous :

final int i = 3;
i = 4; // Error! Cannot modify a "final" object

Il doit être décidable par les compilateurs où la variable avec le finalmarqueur est initialisée, et il ne doit être exécuté qu'une seule fois, sinon la classe ne sera pas compilée. Les mots clés Java finalet C++ constont la même signification lorsqu'ils sont appliqués avec des variables primitives.

const int i = 3; // C++ declaration
i = 4; // Error!

En ce qui finalconcerne les pointeurs, une référence en Java signifie quelque chose de similaire à un constpointeur en C++. En C++, on peut déclarer un "type pointeur constant".

Foo *const bar = mem_location; // const pointer type

Ici, bardoit être initialisé au moment de la déclaration et ne peut plus être modifié, mais ce qu'il pointe est modifiable. C'est-à-dire valide. Il ne peut tout simplement pas pointer vers un autre emplacement. Les références finales en Java fonctionnent de la même manière, sauf qu'elles peuvent être déclarées non initialisées. {{{1}}}

final Foo i; // a Java declaration

Remarque : Java ne prend pas en charge les pointeurs. C'est parce que les pointeurs (avec des restrictions) sont le moyen par défaut d'accéder aux objets en Java, et Java n'utilise pas d'étoiles pour les indiquer. Par exemple, i dans le dernier exemple est un pointeur et peut être utilisé pour accéder à l'instance.

On peut aussi déclarer un pointeur vers des données "en lecture seule" en C++.

const Foo *bar;

Ici barpeut être modifié pour pointer n'importe quoi, n'importe quand ; seule cette valeur pointée ne peut pas être modifiée via le bar pointeur.

Il n'y a pas de mécanisme équivalent en Java. Il n'y a donc pas non plus de constméthodes. La correction constante ne peut pas être appliquée en Java, bien qu'en utilisant des interfaces et en définissant une interface en lecture seule à la classe et en la transmettant, on puisse garantir que les objets peuvent être transmis dans le système d'une manière qui ne peut pas être modifié.

Le framework de collections Java fournit un moyen de créer un wrapper immuable d'un { Collectionvia et des méthodes similaires. Collections.unmodifiableCollection()

Une méthode en Java peut être déclarée "finale", ce qui signifie qu'elle ne peut pas être remplacée dans les sous-classes.

C#

En C# , le qualificateur readonlya le même effet sur les membres de données que le finalfait en Java et le constfait en C++ ; le modificateur consta un effet similaire (mais typé et de classe) à celui du #defineC++. L'autre effet d'inhibition de l'héritage de Java finallorsqu'il est appliqué aux méthodes et aux classes est induit en C# à l'aide du mot-clé sealed.

Contrairement à C++, C# ne permet pas de marquer les méthodes et les paramètres comme const. Cependant, il est également possible de transmettre des sous-classes en lecture seule, et le .NET Framework fournit une prise en charge de la conversion de collections mutables en collections immuables qui peuvent être transmises en tant que wrappers en lecture seule.

Par paradigme

Le traitement des constantes varie considérablement selon le paradigme de programmation . L'exactitude de la constante est un problème dans les langages impératifs comme le C++ car, par défaut, les liaisons de nom créent généralement des variables , qui peuvent varier, comme leur nom l'indique, et donc si l'on souhaite marquer une liaison comme constante, cela nécessite une indication supplémentaire. Dans d'autres paradigmes de langage de programmation, des problèmes liés se posent, avec certains analogues à la correction constante.

Dans la programmation fonctionnelle , les données sont généralement constantes par défaut, plutôt que variables par défaut. Au lieu d'affecter une valeur à une variable (un espace de stockage avec un nom et une valeur potentiellement variable), on crée une liaison d'un nom à une valeur, comme par la letconstruction dans de nombreux dialectes de Lisp . Dans certains langages fonctionnels, en particulier les langages multiparadigmes tels que Common Lisp , la modification des données est courante, tandis que dans d'autres, elle est évitée ou considérée comme exceptionnelle ; c'est le cas de Scheme (un autre dialecte Lisp), qui utilise la set!construction pour modifier les données, avec le ! point d'exclamation attirant l'attention sur ce point. De tels langages atteignent les objectifs de const-correction par défaut, attirant l'attention sur la modification plutôt que sur la constance.

Dans un certain nombre de langages orientés objet , il existe le concept d' objet immuable , qui est particulièrement utilisé pour les types de base comme les chaînes ; les exemples notables incluent Java, JavaScript, Python et C#. Ces langages varient selon que les types définis par l'utilisateur peuvent être marqués comme immuables et peuvent permettre à des champs particuliers (attributs) d'un objet ou d'un type d'être marqués comme immuables.

Dans certains langages multiparadigmes qui autorisent à la fois des styles orientés objet et fonctionnels, ces deux fonctionnalités peuvent être combinées. Par exemple, dans OCaml , les champs d'objet sont immuables par défaut et doivent être explicitement marqués avec le mot-clé mutablepour être mutable, tandis que dans Scala, les liaisons sont explicitement immuables lorsqu'elles sont définies avec valpour "valeur" et explicitement mutables lorsqu'elles sont définies avec varpour "variable".

Conventions de nommage

Les conventions de nommage des constantes varient. Certains les nomment simplement comme n'importe quelle autre variable. D'autres utilisent des majuscules et des traits de soulignement pour les constantes d'une manière similaire à leur utilisation traditionnelle pour les macros symboliques, telles que SOME_CONSTANT. En notation hongroise , un préfixe "k" signifie des constantes ainsi que des macros et des types énumérés .

Une convention imposée est que dans Ruby , toute variable commençant par une majuscule est considérée comme une constante, y compris les noms de classe.

Voir également

Remarques

Les références