Mission (informatique) - Assignment (computer science)

En programmation informatique , une instruction d'affectation définit et/ou réinitialise la valeur stockée dans le ou les emplacements de stockage désignés par un nom de variable  ; en d'autres termes, il copie une valeur dans la variable. Dans la plupart des langages de programmation impératifs , l'instruction d'affectation (ou l'expression) est une construction fondamentale.

Aujourd'hui, la notation la plus couramment utilisée pour cette opération est (à l'origine Superplan 1949-51, popularisé par Fortran 1957 et C ). La deuxième notation la plus couramment utilisée est (à l'origine ALGOL 1958, popularisée par Pascal ),. De nombreuses autres notations sont également utilisées. Dans certaines langues, le symbole utilisé est considéré comme un opérateur (ce qui signifie que l'instruction d'affectation dans son ensemble renvoie une valeur). D'autres langages définissent l'affectation comme une instruction (ce qui signifie qu'elle ne peut pas être utilisée dans une expression). x = exprx := expr

Les affectations permettent généralement à une variable de conserver différentes valeurs à différents moments de sa durée de vie et de sa portée . Cependant, certaines langues (principalement des langues strictement fonctionnelles ) ne permettent pas ce genre de réaffectation « destructive », car cela pourrait impliquer des changements d'état non local. Le but est d'imposer la transparence référentielle , c'est-à-dire des fonctions qui ne dépendent pas de l'état de certaines variables, mais produisent les mêmes résultats pour un ensemble donné d'entrées paramétriques à tout moment. Les programmes modernes dans d'autres langages utilisent également souvent des stratégies similaires, bien que moins strictes, et seulement dans certaines parties, afin de réduire la complexité, normalement en conjonction avec des méthodologies complémentaires telles que la structuration des données , la programmation structurée et l' orientation objet .

Sémantique

Une opération d'affectation est un processus de programmation impérative dans lequel différentes valeurs sont associées à un nom de variable particulier au fil du temps. Le programme, dans un tel modèle, fonctionne en changeant son état à l'aide d'instructions d'affectation successives. Les primitives des langages de programmation impératifs reposent sur l'affectation pour effectuer des itérations . Au niveau le plus bas, l'affectation est mise en œuvre à l'aide d' opérations machine telles que MOVEou STORE.

Les variables sont des conteneurs de valeurs. Il est possible de mettre une valeur dans une variable et de la remplacer plus tard par une nouvelle. Une opération d'affectation modifie l'état courant du programme en cours d'exécution. Par conséquent, l'affectation dépend du concept de variables . Dans un devoir :

  • Le expressionest évalué dans l'état actuel du programme.
  • Le variablese voit attribuer la valeur calculée, remplaçant la valeur précédente de cette variable.

Exemple : En supposant qu'il s'agisse d' aune variable numérique, l'affectation a := 2*asignifie que le contenu de la variable aest doublé après l'exécution de l'instruction.

Un exemple de segment de code C :

int x = 10; 
float y;
x = 23;
y = 32.4f;

Dans cet exemple, la variable xest d'abord déclarée comme un entier, puis la valeur 10 lui est affectée. Notez que la déclaration et l'affectation se produisent dans la même instruction. Dans la deuxième ligne, yest déclaré sans affectation. Dans la troisième ligne, xest réaffectée la valeur de 23. Enfin, yest affectée la valeur de 32,4.

Pour une opération d'affectation, il faut que la valeur de expressionsoit bien définie (c'est une rvalue valide ) et que la variablereprésente une entité modifiable (c'est une lvalue modifiable (non const ) valide ). Dans certains langages, généralement dynamiques , il n'est pas nécessaire de déclarer une variable avant de lui affecter une valeur. Dans de telles langues, une variable est automatiquement déclarée la première fois qu'elle est affectée, avec la portée dans laquelle elle est déclarée variant selon la langue.

Mission unique

Toute affectation qui modifie une valeur existante (par exemple x := x + 1) est interdite dans les langages purement fonctionnels . En programmation fonctionnelle , l'affectation est déconseillée au profit d'une affectation unique, également appelée initialisation . L'affectation unique est un exemple de liaison de nom et diffère de l'affectation décrite dans cet article en ce qu'elle ne peut être effectuée qu'une seule fois, généralement lors de la création de la variable ; aucune réaffectation ultérieure n'est autorisée.

Une évaluation de l'expression n'a pas d' effet secondaire si elle ne modifie pas un état observable de la machine et produit les mêmes valeurs pour la même entrée. L'affectation impérative peut introduire des effets secondaires tout en détruisant et en rendant l'ancienne valeur indisponible tout en la remplaçant par une nouvelle, et est appelée affectation destructive pour cette raison dans LISP et la programmation fonctionnelle , similaire à la mise à jour destructive .

L'affectation unique est la seule forme d'affectation disponible dans les langages purement fonctionnels, tels que Haskell , qui n'ont pas de variables au sens des langages de programmation impératifs mais plutôt des valeurs constantes nommées éventuellement de nature composée avec leurs éléments progressivement définis à la demande . Les langages purement fonctionnels peuvent fournir une opportunité pour que le calcul soit effectué en parallèle , évitant le goulot d' étranglement de von Neumann de l'exécution séquentielle une étape à la fois, car les valeurs sont indépendantes les unes des autres.

Les langages fonctionnels impurs fournissent à la fois une affectation unique ainsi qu'une véritable affectation (bien que la véritable affectation soit généralement utilisée avec moins de fréquence que dans les langages de programmation impératifs). Par exemple, dans Scheme, l'affectation unique (avec let) et l'affectation vraie (avec set!) peuvent être utilisées sur toutes les variables, et des primitives spécialisées sont fournies pour une mise à jour destructive à l'intérieur des listes, des vecteurs, des chaînes, etc. En OCaml, une seule affectation est autorisée pour les variables, via la syntaxe ; cependant, la mise à jour destructive peut être utilisée sur des éléments de tableaux et de chaînes avec un opérateur séparé , ainsi que sur des champs d'enregistrements et d'objets qui ont été explicitement déclarés mutables (c'est-à-dire susceptibles d'être modifiés après leur déclaration initiale) par le programmeur. let name = value<-

Les langages de programmation fonctionnels qui utilisent une affectation unique incluent Clojure (pour les structures de données, pas les vars), Erlang (il accepte les affectations multiples si les valeurs sont égales, contrairement à Haskell), F# , Haskell , JavaScript (pour les constantes), Lava , OCaml , Oz (pour les variables de flux de données, pas les cellules), Racket (pour certaines structures de données comme les listes, pas les symboles), SASL , Scala (pour les vals), SISAL , Standard ML . Le code Prolog sans retour en arrière peut être considéré comme une affectation unique explicite , explicite dans le sens où ses variables (nommées) peuvent être dans un état explicitement non affecté, ou être définies exactement une fois. En Haskell, en revanche, il ne peut y avoir de variables non affectées, et chaque variable peut être considérée comme étant implicitement définie sur sa valeur (ou plutôt sur un objet de calcul qui produira sa valeur à la demande ) lors de sa création.

Valeur d'une mission

Dans certains langages de programmation, une instruction d'affectation renvoie une valeur, alors que dans d'autres, ce n'est pas le cas.

Dans la plupart des langages de programmation orientés expression (par exemple, C ), l'instruction d'affectation renvoie la valeur affectée, autorisant des idiomes tels que x = y = a, dans lesquels l'instruction d'affectation y = arenvoie la valeur de a, qui est ensuite affectée à x. Dans une instruction telle que , la valeur de retour d'une fonction est utilisée pour contrôler une boucle tout en affectant cette même valeur à une variable. while ((ch = getchar()) != EOF) {}

Dans d'autres langages de programmation, Scheme par exemple, la valeur de retour d'une affectation n'est pas définie et de tels idiomes ne sont pas valides.

En Haskell , il n'y a pas d'affectation de variable ; mais les opérations similaires à l'affectation (comme l'affectation à un champ d'un tableau ou à un champ d'une structure de données modifiable) évaluent généralement le type d'unité , qui est représenté par (). Ce type n'a qu'une seule valeur possible, donc ne contient aucune information. C'est généralement le type d'expression qui est évalué uniquement pour ses effets secondaires.

Formes variantes d'affectation

Certains modèles d'utilisation sont très courants et ont donc souvent une syntaxe spéciale pour les prendre en charge. Il s'agit principalement de sucre syntaxique pour réduire la redondance dans le code source, mais aide également les lecteurs du code à comprendre l'intention du programmeur et fournit au compilateur un indice sur une optimisation possible.

Mission augmentée

Le cas où la valeur attribuée dépend d'une précédente est si fréquent que de nombreux langages impératifs, notamment C et la majorité de ses descendants, fournissent des opérateurs spéciaux appelés affectation augmentée , comme *=, et a = 2*apeuvent donc être écrits sous la forme a *= 2. Au-delà du sucre syntaxique, cela aide la tâche du compilateur en précisant que la modification sur place de la variable aest possible.

Affectation chaînée

Une instruction comme w = x = y = zest appelée une affectation chaînée dans laquelle la valeur de zest affectée à plusieurs variables w, x,et y. Les affectations chaînées sont souvent utilisées pour initialiser plusieurs variables, comme dans

a = b = c = d = f = 0

Tous les langages de programmation ne prennent pas en charge l'affectation chaînée. Les devoirs enchaînés sont équivalents à une séquence de devoirs, mais la stratégie d'évaluation diffère selon les langues. Pour les affectations chaînées simples, comme l'initialisation de plusieurs variables, la stratégie d'évaluation n'a pas d'importance, mais si les cibles (valeurs l) de l'affectation sont liées d'une manière ou d'une autre, la stratégie d'évaluation affecte le résultat.

Dans certains langages de programmation ( C par exemple), les affectations chaînées sont prises en charge car les affectations sont des expressions et ont des valeurs. Dans ce cas, l'affectation de chaîne peut être implémentée en ayant une affectation associative à droite , et les affectations se font de droite à gauche. Par exemple, i = arr[i] = f()équivaut à arr[i] = f(); i = arr[i]. En C++, ils sont également disponibles pour les valeurs des types de classe en déclarant le type de retour approprié pour l'opérateur d'affectation.

En Python , les instructions d'affectation ne sont pas des expressions et n'ont donc pas de valeur. Au lieu de cela, les affectations chaînées sont une série d'instructions avec plusieurs cibles pour une seule expression. Les affectations sont exécutées de gauche à droite afin d' i = arr[i] = f()évaluer l'expression f(), puis d'affecter le résultat à la cible la plus à gauche, i, puis d'affecter le même résultat à la cible suivante, arr[i], en utilisant la nouvelle valeur de i. Ceci est essentiellement équivalent à tmp = f(); i = tmp; arr[i] = tmpbien qu'aucune variable réelle ne soit produite pour la valeur temporaire.

Affectation parallèle

Certains langages de programmation, tels que APL , Common Lisp , Go , JavaScript (depuis 1.7), PHP , Maple , Lua , occam 2 , Perl , Python , REBOL , Ruby , et PowerShell permettent d'affecter plusieurs variables en parallèle, avec une syntaxe comme :

a, b := 0, 1

qui affecte simultanément 0 à aet 1 à b. Ceci est le plus souvent connu sous le nom d' affectation parallèle ; il a été introduit dans CPL en 1963, sous le nom d'affectation simultanée , et est parfois appelé affectation multiple , bien que cela prête à confusion lorsqu'il est utilisé avec "affectation unique", car ce ne sont pas des opposés. Si le côté droit de l'affectation est une variable unique (par exemple un tableau ou une structure), la fonctionnalité est appelée affectation de décompactage ou de déstructuration :

var list := {0, 1}
a, b := list

La liste sera décompressée de sorte que 0 soit attribué à aet 1 à b. Par ailleurs,

a, b := b, a

échange les valeurs de aet b. Dans les langues sans affectation parallèle, cela devrait être écrit pour utiliser une variable temporaire

var t := a
a := b
b := t

puisque a := b; b := alaisse les deux aet bavec la valeur d'origine de b.

Certains langages, tels que Go et Python, combinent l'affectation parallèle, les tuples et le déballage automatique des tuples pour autoriser plusieurs valeurs de retour à partir d'une seule fonction, comme dans cet exemple Python,

def f():
    return 1, 2
a, b = f()

tandis que d'autres langages, tels que C# , illustrés ici, nécessitent une construction et une déconstruction explicites de tuples avec des parenthèses :

(a, b) = (b, a);
(string, int) f() => ("foo", 1);
var (a, b) = f();

Cela fournit une alternative à l'utilisation de paramètres de sortie pour renvoyer plusieurs valeurs à partir d'une fonction. Cela remonte à CLU (1974), et CLU a aidé à populariser l'affectation parallèle en général.

C# permet en outre une affectation de déconstruction généralisée avec une implémentation définie par l'expression sur le côté droit, car le compilateur recherche une instance ou une méthode d' extension appropriée Deconstructsur l'expression, qui doit avoir des paramètres de sortie pour les variables affectées. Par exemple, une telle méthode qui donnerait à la classe qu'elle apparaît dans le même comportement que la valeur de retour f()ci-dessus serait

void Deconstruct(out string a, out int b) { a = "foo"; b = 1; }

En C et C++, l' opérateur virgule est similaire à l'affectation parallèle en permettant à plusieurs affectations de se produire dans une seule instruction, en écrivant a = 1, b = 2au lieu de a, b = 1, 2. Ceci est principalement utilisé dans les boucles for , et est remplacé par une affectation parallèle dans d'autres langages tels que Go. Cependant, le code C++ ci-dessus ne garantit pas une simultanéité parfaite, puisque le côté droit du code suivant a = b, b = a+1est évalué après le côté gauche. Dans des langages tels que Python, a, b = b, a+1affectera les deux variables simultanément, en utilisant la valeur initiale de a pour calculer le nouveau b.

Affectation versus égalité

L'utilisation du signe égal =comme opérateur d'affectation a été fréquemment critiquée, en raison du conflit avec les égaux comme comparaison pour l'égalité. Cela entraîne à la fois une confusion chez les novices dans l'écriture de code, et une confusion même chez les programmeurs expérimentés dans la lecture de code. L'utilisation d'égaux pour l'affectation remonte au langage Superplan de Heinz Rutishauser , conçu de 1949 à 1951, et a été particulièrement popularisé par Fortran :

Un exemple notoire de mauvaise idée était le choix du signe égal pour désigner l'affectation. Il remonte à Fortran en 1957 et a été copié aveuglément par des armées de concepteurs de langages. Pourquoi est-ce une mauvaise idée? Parce qu'il renverse une tradition centenaire de laisser « = » désigner une comparaison pour l'égalité, un prédicat qui est soit vrai, soit faux. Mais Fortran l'a fait pour signifier la cession, l'application de l'égalité. Dans ce cas, les opérandes sont sur un pied d'égalité : L'opérande de gauche (une variable) doit être égal à l'opérande de droite (une expression). x = y ne veut pas dire la même chose que y = x.

—  Niklaus Wirth , Les bonnes idées, à travers le miroir

Les programmeurs débutants confondent parfois l'affectation avec l' opérateur relationnel pour l'égalité, car "=" signifie égalité en mathématiques et est utilisé pour l'affectation dans de nombreuses langues. Mais l'affectation modifie la valeur d'une variable, tandis que le test d'égalité teste si deux expressions ont la même valeur.

Dans certains langages, tels que BASIC , un seul signe égal ( "=") est utilisé à la fois pour l'opérateur d'affectation et l'opérateur relationnel d'égalité, le contexte déterminant ce qui est signifié. D'autres langues utilisent des symboles différents pour les deux opérateurs. Par exemple:

  • Dans ALGOL et Pascal , l'opérateur d'affectation est un deux-points et un signe égal ( ":=") tandis que l'opérateur d'égalité est un simple égal ( "=").
  • En C , l'opérateur d'affectation est un seul signe égal ( "=") tandis que l'opérateur d'égalité est une paire de signes égal ( "==").
  • Dans R , l'opérateur d'affectation est fondamentalement <-, comme dans x <- value, mais un seul signe égal peut être utilisé dans certains contextes.

La similitude entre les deux symboles peut conduire à des erreurs si le programmeur oublie quelle forme (" =", " ==", " :=") est appropriée, ou saisit mal " =" quand " ==" était prévu. Il s'agit d'un problème de programmation courant avec des langages tels que C (y compris une célèbre tentative de backdoor du noyau Linux), où l'opérateur d'affectation renvoie également la valeur attribuée (de la même manière qu'une fonction renvoie une valeur), et peut être valablement imbriqué à l'intérieur des expressions. Si l'intention était de comparer deux valeurs dans une ifinstruction, par exemple, une affectation est tout à fait susceptible de renvoyer une valeur interprétable comme booléenne true, auquel cas la thenclause sera exécutée, conduisant le programme à se comporter de manière inattendue. Certains processeurs de langage (tels que gcc ) peuvent détecter de telles situations et avertir le programmeur de l'erreur potentielle.

Notation

Les deux représentations les plus courantes pour l'affectation de copie sont le signe égal ( =) et les deux-points égaux ( :=). Les deux formes peuvent désigner sémantiquement soit une instruction d' affectation , soit un opérateur d' affectation (qui a également une valeur), selon la langue et/ou l'usage.

variable = expression Fortran , PL/I , C (et descendants tels que C++ , Java , etc.), Bourne shell , Python , Go (affectation à des variables pré-déclarées), R , PowerShell , Nim , etc.
variable := expression ALGOL (et dérivés), Simula , CPL , BCPL , Pascal (et descendants tels que Modula ), Mary , PL/M , Ada , Smalltalk , Eiffel , Oberon , Dylan , Seed7 , Python (une expression d'affectation), Go (abréviation de déclarer et définir une variable), Io , AMPL , ML , AutoHotkey etc.

D'autres possibilités incluent une flèche vers la gauche ou un mot-clé, bien qu'il existe d'autres variantes, plus rares :

variable << expression Magik
variable <- expression F# , OCaml , R , S
variable <<- expression R
assign("variable", expression) R
variableexpression APL , Smalltalk , Programmation BASIC
variable =: expression J
LET variable = expression DE BASE
let variable := expression XQuery
set variable to expression AppleScript
set variable = expression coque C
Set-Variable variable (expression) PowerShell
variable : expression Macsyma, Maxima , K
variable: expression Rebol
var variable expression langage de script mIRC
reference-variable :- reference-expression Simulateur

Les affectations de pseudo-codes mathématiques sont généralement représentées par une flèche vers la gauche.

Certaines plateformes mettent l'expression à gauche et la variable à droite :

MOVE expression TO variable COBOL
expressionvariable TI-BASIC , Casio BASIC
expression -> variable POP-2 , BÊTA , R
put expression into variable Code en direct
PUT expression IN variable abc

Certains langages orientés expression, tels que Lisp et Tcl, utilisent uniformément la syntaxe de préfixe (ou de suffixe) pour toutes les instructions, y compris l'affectation.

(setf variable expression) Lisp commun
(set! variable expression) Schème
set variable expression Tcl
expression variable ! En avant

Voir également

Remarques

Les références