Asignación (informática) - Assignment (computer science)

En la programación informática , una declaración de asignación establece y / o restablece el valor almacenado en la ubicación o ubicaciones de almacenamiento indicadas por un nombre de variable ; en otras palabras, copia un valor en la variable. En la mayoría de los lenguajes de programación imperativos , la declaración de asignación (o expresión) es una construcción fundamental.

En la actualidad, la notación más utilizada para esta operación es (originalmente Superplan 1949–51, popularizado por Fortran 1957 y C ). La segunda notación más utilizada es (originalmente ALGOL 1958, popularizada por Pascal ). También se utilizan muchas otras notaciones. En algunos idiomas, el símbolo utilizado se considera un operador (lo que significa que la declaración de asignación en su conjunto devuelve un valor). Otros lenguajes definen la asignación como una declaración (lo que significa que no se puede usar en una expresión). x = exprx := expr

Las asignaciones generalmente permiten que una variable tenga diferentes valores en diferentes momentos durante su vida útil y alcance . Sin embargo, algunos lenguajes (principalmente lenguajes estrictamente funcionales ) no permiten ese tipo de reasignación "destructiva", ya que podría implicar cambios de estado no local. El propósito es hacer cumplir la transparencia referencial , es decir, funciones que no dependen del estado de algunas variables, pero producen los mismos resultados para un conjunto dado de entradas paramétricas en cualquier momento. Los programas modernos en otros lenguajes también suelen utilizar estrategias similares, aunque menos estrictas, y solo en determinadas partes, para reducir la complejidad, normalmente junto con metodologías complementarias como la estructuración de datos , la programación estructurada y la orientación a objetos .

Semántica

Una operación de asignación es un proceso en programación imperativa en el que diferentes valores se asocian con un nombre de variable particular a medida que pasa el tiempo. El programa, en tal modelo, opera cambiando su estado usando sucesivas sentencias de asignación. Las primitivas de los lenguajes de programación imperativos se basan en la asignación para realizar la iteración . En el nivel más bajo, la asignación se implementa utilizando operaciones de máquina como MOVEo STORE.

Las variables son contenedores de valores. Es posible poner un valor en una variable y luego reemplazarlo por uno nuevo. Una operación de asignación modifica el estado actual del programa en ejecución. En consecuencia, la asignación depende del concepto de variables . En una tarea:

  • Se expressionevalúa en el estado actual del programa.
  • Se variablele asigna el valor calculado, reemplazando el valor anterior de esa variable.

Ejemplo: asumiendo que aes una variable numérica, la asignación a := 2*asignifica que el contenido de la variable ase duplica después de la ejecución de la declaración.

Un segmento de ejemplo de código C :

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

En este ejemplo, la variable xse declara primero como un int y luego se le asigna el valor de 10. Observe que la declaración y la asignación ocurren en la misma instrucción. En la segunda línea, yse declara sin asignación. En la tercera línea, xse reasigna el valor de 23. Finalmente, yse asigna el valor de 32,4.

Para una operación de asignación, es necesario que el valor de la expressionestá bien definido (es un válido rvalue ) y que la variablerepresenta una entidad modificable (es un modificable válida (no const ) lvalue ). En algunos lenguajes, típicamente dinámicos , no es necesario declarar una variable antes de asignarle un valor. En tales lenguajes, una variable se declara automáticamente la primera vez que se le asigna, con el alcance que se declara variando según el idioma.

Asignación única

Cualquier asignación que cambie un valor existente (por ejemplo x := x + 1) no está permitida en lenguajes puramente funcionales . En la programación funcional , se desaconseja la asignación en favor de la asignación única, también llamada inicialización . La asignación única es un ejemplo de vinculación de nombres y se diferencia de la asignación descrita en este artículo en que solo se puede realizar una vez, generalmente cuando se crea la variable; no se permite ninguna reasignación posterior.

Una evaluación de expresión no tiene un efecto secundario si no cambia un estado observable de la máquina y produce los mismos valores para la misma entrada. La asignación imperativa puede introducir efectos secundarios al destruir y hacer que el valor anterior no esté disponible al sustituirlo por uno nuevo, y por esa razón se denomina asignación destructiva en LISP y programación funcional , similar a la actualización destructiva .

La asignación única es la única forma de asignación disponible en lenguajes puramente funcionales, como Haskell , que no tienen variables en el sentido de lenguajes de programación imperativos, sino valores constantes nombrados posiblemente de naturaleza compuesta con sus elementos definidos progresivamente bajo demanda . Los lenguajes puramente funcionales pueden brindar una oportunidad para que los cálculos se realicen en paralelo , evitando el cuello de botella de von Neumann de la ejecución secuencial de un paso a la vez, ya que los valores son independientes entre sí.

Los lenguajes funcionales impuros proporcionan tanto una asignación única como una asignación verdadera (aunque la asignación verdadera se usa típicamente con menos frecuencia que en los lenguajes de programación imperativos). Por ejemplo, en Scheme, tanto la asignación única (con let) como la asignación verdadera (con set!) se pueden usar en todas las variables, y se proporcionan primitivas especializadas para actualizaciones destructivas dentro de listas, vectores, cadenas, etc. En OCaml, solo se permite una asignación única para variables, a través de la sintaxis; sin embargo, la actualización destructiva se puede utilizar en elementos de matrices y cadenas con un operador separado , así como en campos de registros y objetos que el programador ha declarado explícitamente mutables (es decir, capaces de ser cambiados después de su declaración inicial). let name = value<-

Los lenguajes de programación funcional que usan asignación única incluyen Clojure (para estructuras de datos, no vars), Erlang (acepta asignación múltiple si los valores son iguales, en contraste con Haskell), F # , Haskell , JavaScript (para constantes), Lava , OCaml , Oz (para variables de flujo de datos, no celdas), Racket (para algunas estructuras de datos como listas, no símbolos), SASL , Scala (para vals), SISAL , Standard ML . El código de Prolog sin retroceso puede considerarse una asignación única explícita , explícita en el sentido de que sus variables (nombradas) pueden estar en un estado explícitamente sin asignar, o establecerse exactamente una vez. En Haskell, por el contrario, no puede haber variables sin asignar, y se puede pensar que cada variable se establece implícitamente en su valor (o más bien en un objeto computacional que producirá su valor a pedido ) cuando se crea.

Valor de una asignación

En algunos lenguajes de programación, una instrucción de asignación devuelve un valor, mientras que en otros no.

En la mayoría de los lenguajes de programación orientados a expresiones (por ejemplo, C ), la declaración de asignación devuelve el valor asignado, permitiendo expresiones idiomáticas como x = y = a, en las que la declaración de asignación y = adevuelve el valor de a, que luego se asigna a x. En una declaración como , el valor de retorno de una función se usa para controlar un bucle mientras se asigna el mismo valor a una variable. while ((ch = getchar()) != EOF) {}

En otros lenguajes de programación, Scheme por ejemplo, el valor de retorno de una asignación no está definido y tales modismos no son válidos.

En Haskell , no hay asignación de variables; pero las operaciones similares a la asignación (como asignar a un campo de una matriz o un campo de una estructura de datos mutable) generalmente evalúan el tipo de unidad , que se representa como (). Este tipo solo tiene un valor posible, por lo que no contiene información. Por lo general, es el tipo de expresión que se evalúa únicamente por sus efectos secundarios.

Formas variantes de asignación

Ciertos patrones de uso son muy comunes y, por lo tanto, a menudo tienen una sintaxis especial para respaldarlos. Estos son principalmente azúcar sintáctico para reducir la redundancia en el código fuente, pero también ayudan a los lectores del código a comprender la intención del programador y proporcionan al compilador una pista para una posible optimización.

Asignación aumentada

El caso en el que el valor asignado depende de uno anterior es tan común que muchos lenguajes imperativos, sobre todo C y la mayoría de sus descendientes, proporcionan operadores especiales llamados asignación aumentada , como *=, por a = 2*alo que en su lugar se pueden escribir como a *= 2. Más allá del azúcar sintáctico, esto ayuda a la tarea del compilador al dejar en claro que aes posible la modificación in situ de la variable .

Asignación encadenada

Una declaración como w = x = y = zse llama asignación encadenada en la que el valor de zse asigna a múltiples variables w, x,y y. Las asignaciones encadenadas se utilizan a menudo para inicializar múltiples variables, como en

a = b = c = d = f = 0

No todos los lenguajes de programación admiten la asignación encadenada. Las asignaciones encadenadas equivalen a una secuencia de asignaciones, pero la estrategia de evaluación difiere entre los idiomas. Para asignaciones encadenadas simples, como inicializar múltiples variables, la estrategia de evaluación no importa, pero si los objetivos (valores l) en la asignación están conectados de alguna manera, la estrategia de evaluación afecta el resultado.

En algunos lenguajes de programación ( C por ejemplo), las asignaciones encadenadas son compatibles porque las asignaciones son expresiones y tienen valores. En este caso, la asignación en cadena se puede implementar con una asignación asociativa por la derecha , y las asignaciones ocurren de derecha a izquierda. Por ejemplo, i = arr[i] = f()es equivalente a arr[i] = f(); i = arr[i]. En C ++ también están disponibles para valores de tipos de clase al declarar el tipo de retorno apropiado para el operador de asignación.

En Python , las declaraciones de asignación no son expresiones y, por lo tanto, no tienen valor. En cambio, las asignaciones encadenadas son una serie de declaraciones con múltiples destinos para una sola expresión. Las asignaciones se ejecutan de izquierda a derecha para que i = arr[i] = f()evalúe la expresión f(), luego asigne el resultado al objetivo situado más a la izquierda i, y luego asigne el mismo resultado al siguiente objetivo arr[i], utilizando el nuevo valor de i. Esto es esencialmente equivalente a, tmp = f(); i = tmp; arr[i] = tmpaunque no se produce una variable real para el valor temporal.

Asignación paralela

Algunos lenguajes de programación, como APL , Common Lisp , Go , JavaScript (desde 1.7), PHP , Maple , Lua , occam 2 , Perl , Python , REBOL , Ruby y PowerShell permiten asignar varias variables en paralelo, con sintaxis como :

a, b := 0, 1

que asigna simultáneamente 0 ay a1 a b. Esto se conoce con mayor frecuencia como asignación en paralelo ; fue introducido en CPL en 1963, bajo el nombre de asignación simultánea , y algunas veces se le llama asignación múltiple , aunque esto es confuso cuando se usa con "asignación única", ya que no son opuestos. Si el lado derecho de la asignación es una sola variable (por ejemplo, una matriz o estructura), la función se denomina asignación de desempaquetado o desestructuración :

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

La lista se descomprimirá de modo que se asigne 0 ay a1 a b. Es más,

a, b := b, a

intercambia los valores de ay b. En idiomas sin asignación paralela, esto debería escribirse para usar una variable temporal

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

ya que a := b; b := adeja ambos ay bcon el valor original de b.

Algunos lenguajes, como Go y Python, combinan asignación paralela, tuplas y desempaquetado automático de tuplas para permitir múltiples valores de retorno de una sola función, como en este ejemplo de Python,

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

mientras que otros lenguajes, como C # , que se muestran aquí, requieren la construcción y deconstrucción de tuplas explícitas con paréntesis:

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

Esto proporciona una alternativa al uso de parámetros de salida para devolver múltiples valores de una función. Esto se remonta a CLU (1974), y CLU ayudó a popularizar la asignación paralela en general.

Además, C # permite la asignación de deconstrucción generalizada con la implementación definida por la expresión del lado derecho, ya que el compilador busca una instancia apropiada o un método de extensión Deconstruct en la expresión, que debe tener parámetros de salida para las variables a las que se asignan. Por ejemplo, uno de esos métodos que daría a la clase que aparece en el mismo comportamiento que el valor de retorno f()anterior sería

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

En C y C ++, el operador de coma es similar a la asignación paralela al permitir que ocurran múltiples asignaciones dentro de una sola declaración, escribiendo en a = 1, b = 2lugar de a, b = 1, 2. Esto se usa principalmente en bucles for y se reemplaza por asignación paralela en otros idiomas como Go. Sin embargo, el código C ++ anterior no garantiza una simultaneidad perfecta, ya que el lado derecho del siguiente código a = b, b = a+1se evalúa después del lado izquierdo. En lenguajes como Python, a, b = b, a+1asignará las dos variables al mismo tiempo, utilizando el valor inicial de a para calcular el nuevo b.

Asignación versus igualdad

El uso del signo igual =como operador de asignación ha sido criticado con frecuencia, debido al conflicto con iguales como comparación para la igualdad. Esto da como resultado tanto confusión para los principiantes al escribir código como confusión incluso para programadores experimentados en la lectura de código. El uso de iguales para la asignación se remonta al Superplan de lenguaje de Heinz Rutishauser , diseñado entre 1949 y 1951, y fue particularmente popularizado por Fortran:

Un ejemplo notorio de una mala idea fue la elección del signo igual para denotar la asignación. Se remonta a Fortran en 1957 y ha sido copiada a ciegas por ejércitos de diseñadores de lenguajes. por qué es una mala idea? Porque derroca una tradición centenaria dejar que “=” denote una comparación para la igualdad, un predicado que es verdadero o falso. Pero Fortran lo hizo para significar asignación, el cumplimiento de la igualdad. En este caso, los operandos están en pie de igualdad: el operando izquierdo (una variable) se igualará al operando derecho (una expresión). x = y no significa lo mismo que y = x.

-  Niklaus Wirth , Buenas ideas, a través del espejo

Los programadores principiantes a veces confunden la asignación con el operador relacional para la igualdad, ya que "=" significa igualdad en matemáticas y se usa para la asignación en muchos idiomas. Pero la asignación altera el valor de una variable, mientras que la prueba de igualdad comprueba si dos expresiones tienen el mismo valor.

En algunos lenguajes, como BASIC , "="se usa un solo signo igual ( ) tanto para el operador de asignación como para el operador relacional de igualdad, y el contexto determina a qué se refiere. Otros idiomas usan símbolos diferentes para los dos operadores. Por ejemplo:

  • En ALGOL y Pascal , el operador de asignación es un signo de dos puntos y un signo igual ( ":=") mientras que el operador de igualdad es un único igual ( "=").
  • En C , el operador de asignación es un solo signo igual ( "=") mientras que el operador de igualdad es un par de signos iguales ( "==").
  • En R , el operador de asignación es básicamente <-, como en x <- value, pero se puede usar un solo signo igual en ciertos contextos.

La similitud en los dos símbolos puede conducir a errores si el programador olvida qué forma (" =", " ==", " :=") es apropiada, o escribe incorrectamente " =" cuando " ==" estaba previsto. Este es un problema de programación común con lenguajes como C (incluido un famoso intento de puerta trasera del kernel de Linux), donde el operador de asignación también devuelve el valor asignado (de la misma manera que una función devuelve un valor), y se puede anidar válidamente expresiones internas. Si la intención era comparar dos valores en una ifdeclaración, por ejemplo, es muy probable que una asignación devuelva un valor interpretable como booleano verdadero, en cuyo caso la thencláusula se ejecutará, lo que hará que el programa se comporte de manera inesperada. Algunos procesadores de lenguaje (como gcc ) pueden detectar tales situaciones y advertir al programador del posible error.

Notación

Las dos representaciones más comunes para la asignación de copia son el signo igual ( =) y los dos puntos iguales ( :=). Ambas formas pueden denotar semánticamente una declaración de asignación o un operador de asignación (que también tiene un valor), según el idioma y / o el uso.

variable = expression Fortran , PL / I , C (y descendientes como C ++ , Java , etc.), Bourne shell , Python , Go (asignación a variables pre-declaradas), R , PowerShell , Nim , etc.
variable := expression ALGOL (y derivados), Simula , CPL , BCPL , Pascal (y descendientes como Modula ), Mary , PL / M , Ada , Smalltalk , Eiffel , Oberon , Dylan , Seed7 , Python (una expresión de asignación), Go (abreviatura de declarando y definiendo una variable), Io , AMPL , ML , AutoHotkey , etc.

Otras posibilidades incluyen una flecha hacia la izquierda o una palabra clave, aunque hay otras variantes más raras:

variable << expression Magik
variable <- expression F # , OCaml , R , S
variable <<- expression R
assign("variable", expression) R
variableexpression APL , Smalltalk , Programación BÁSICA
variable =: expression J
LET variable = expression BÁSICO
let variable := expression XQuery
set variable to expression AppleScript
set variable = expression Cáscara de C
Set-Variable variable (expression) Potencia Shell
variable : expression Macsyma, Maxima , K
variable: expression Rebol
var variable expression lenguaje de secuencias de comandos mIRC
reference-variable :- reference-expression Simula

Las asignaciones de pseudocódigo matemático generalmente se representan con una flecha hacia la izquierda.

Algunas plataformas ponen la expresión a la izquierda y la variable a la derecha:

MOVE expression TO variable COBOL
expressionvariable TI-BASIC , Casio BASIC
expression -> variable POP-2 , BETA , R
put expression into variable LiveCode
PUT expression IN variable A B C

Algunos lenguajes orientados a expresiones, como Lisp y Tcl, usan uniformemente la sintaxis de prefijo (o sufijo) para todas las declaraciones, incluida la asignación.

(setf variable expression) Lisp común
(set! variable expression) Esquema
set variable expression Tcl
expression variable ! Adelante

Ver también

Notas

Referencias