La asignación es un mecanismo vinculante en la programación que le permite cambiar dinámicamente la relación de los nombres de los objetos de datos (generalmente variables ) con sus valores. Estrictamente hablando, el cambio de valores es un efecto secundario de la operación de asignación y, en muchos lenguajes de programación modernos, la operación en sí también devuelve algún resultado (generalmente una copia del valor asignado). A nivel físico, el resultado de una operación de asignación es escribir y reescribir celdas de memoria o registros del procesador .
La asignación es una de las construcciones centrales en los lenguajes de programación imperativos , implementada de manera eficiente y simple en la arquitectura de von Neumann que es la base de las computadoras modernas .
En los lenguajes de programación orientados a objetos, la semántica de asignación es bastante diferente. Por ejemplo, en el lenguaje Kotlin , al asignar, el objeto se copia, y en el lenguaje Rust , el objeto se mueve (move-semantics) y el paquete antiguo deja de ser válido.
La programación lógica adopta un enfoque algebraico diferente. Aquí no hay una asignación ordinaria ("destructiva"). Solo hay incógnitas que aún no se han calculado e identificadores correspondientes para indicar esas incógnitas. El programa solo determina sus valores, ellos mismos son constantes. Por supuesto, en la implementación, el programa escribe en la memoria, pero los lenguajes de programación no reflejan esto, lo que le da al programador la oportunidad de trabajar con identificadores de valores constantes y no con variables.
La programación funcional pura no usa variables y no necesita una declaración de asignación explícita.
La sintaxis general para una asignación simple es la siguiente:
<expresión a la izquierda> <operador de asignación> <expresión a la derecha>La "expresión de la izquierda", después de la evaluación, debe conducir a la ubicación del objeto de datos, a la variable de destino, el identificador de la celda de memoria en la que se realizará la grabación. Estas referencias se denominan "valores izquierdos" ( lvalue en inglés ). Los ejemplos típicos de un valor para zurdos son un nombre de variable ( ), una ruta a una variable en el espacio de nombres y bibliotecas ( ), una ruta de matriz con una expresión en lugar del índice ( ), pero más adelante se brindan opciones más complejas en este artículo. xNamespace.Library.Object.AnotherObject.Propertythis.a[i+j*k]
La "expresión de la derecha" debe denotar de una forma u otra el valor a asignar al objeto de datos. Por lo tanto, incluso si el nombre de la misma variable está a la derecha como a la izquierda, se interpreta de manera diferente; tales referencias se denominan "valores de la mano derecha" ( rvalue en inglés ). El lenguaje utilizado impone restricciones adicionales a la expresión : por lo tanto, en lenguajes tipificados estáticamente , debe tener el mismo tipo que la variable de destino, o un tipo convertido a ella; en algunos lenguajes (por ejemplo, C o Python ), también se puede incluir otro operador de asignación ( ) en la expresión.a=b=c
El operador de asignación más común en los lenguajes de programación es =, :=o ←. Pero es posible que no se introduzca una sintaxis especial, por ejemplo, en Tcl :
establecer <variable_objetivo> <expresión>Esta notación es equivalente a llamar a una función . Del mismo modo, en COBOL de estilo antiguo :
MULTIPLICA 2 POR 2 DANDO CUATRO.La elección del símbolo de asignación es motivo de controversia entre los diseñadores de lenguajes. Existe la opinión de que el uso de un símbolo =para la asignación confunde a los programadores y también plantea la cuestión de elegir un símbolo para el operador de comparación , que es difícil de resolver bien .
Así, Niklaus Wirth afirmó [1] :
Un mal ejemplo bien conocido es la elección de un signo igual para denotar una asignación, que se remonta a Fortran en 1957 y todavía se repite ciegamente por una gran cantidad de desarrolladores de lenguajes. Esta mala idea echa por tierra la antigua tradición de usar el signo " = " para denotar una comparación de igualdad, un predicado que se evalúa como " verdadero " o " falso ". Pero en Fortran, este símbolo comenzó a denotar asignación, coerción a la igualdad. En este caso, los operandos están en una posición desigual: el operando izquierdo, la variable, debe igualarse al operando derecho, la expresión. Entonces x = y no significa lo mismo que y = x.
Texto original (inglés)[ mostrarocultar] Un ejemplo notorio de una mala idea fue la elección del signo igual para indicar la asignación. Se remonta a Fortran en 1957 y ha sido copiado a ciegas por ejércitos de diseñadores de lenguajes. por qué es una mala idea? Porque derroca una tradición de un siglo de dejar que "=" denote una comparación de igualdad, un predicado que es verdadero o falso. Pero Fortran hizo que significara asignación, la aplicación de la igualdad. En este caso, los operandos están en pie de igualdad: el operando izquierdo (una variable) debe ser igual al operando derecho (una expresión). x = y no significa lo mismo que y = x. [2]La implementación de esta posición de Wirth se puede considerar que en el lenguaje Pascal , del cual es autor, el operador de asignación es :=, mientras que para la comparación simplemente se usa =.
La elección del símbolo del operador de igualdad en el lenguaje cuando se usa =como una asignación se decide por:
La notación de igualdad en C == es una fuente de errores frecuentes debido a la posibilidad de usar asignación en construcciones de control, pero en otros lenguajes el problema se resuelve introduciendo restricciones adicionales.
Por ejemplo, en la expresión de lenguaje PL/1 :
A = B = Ca la variable se Аle asigna el valor booleano de la expresión de relación В = С. Tal notación conduce a una legibilidad reducida y rara vez se usa.
Lejos de ser siempre "intuitiva" (para los programadores de lenguajes imperativos), la forma de interpretar la tarea es la única verdadera y posible.
A partir de la sintaxis utilizada en los lenguajes imperativos, no siempre es posible comprender cómo se implementa la semántica de asignación a menos que esté explícitamente definida en el lenguaje.
Por ejemplo, en Forth , antes de la asignación, el valor y la dirección de una variable deben ir a la pila de datos, y esto se puede hacer mucho antes de que se realice la asignación real.
Ejemplo:
\ Definiendo la variable AAA y asignándole el valor 10 en la siguiente línea AAA VARIABLES 10 AAA!Lo mismo un poco diferente:
diez AAA VARIABLES AAA! AmbigüedadConsidere un ejemplo:
X=2+1Esto puede entenderse como "el resultado del cálculo 2+1 (es decir, 3) se asigna a una variable X" o como "la operación 2+1 se asigna a una variable X". Si el lenguaje se escribe estáticamente , entonces no hay ambigüedad, se resuelve por el tipo de la variable X("entero" u "operación"). En Prolog , la escritura es dinámica , por lo que existen dos operaciones de asignación: is - asignación de un valor equivalente y = - asignación de un patrón. En este caso:
X es 2 + 1, X = 3 X=2+1, X=3La primera secuencia será reconocida como verdadera, la segunda, falsa.
TextoCuando se trata de objetos de gran tamaño y estructura compleja, muchos lenguajes utilizan la llamada " semántica de referencia ". Esto significa que no se produce la asignación en el sentido clásico, pero se considera que el valor de la variable de destino está ubicado en el mismo lugar que el valor de la variable de origen. Por ejemplo ( Pitón ):
un = [1, 2, 3] b = un un[1] = 1000Después de eso, btendrá un valor [1, 1000, 3] , simplemente porque, de hecho, su valor es el valor de a. El número de referencias al mismo objeto de datos se llama su cardinalidad, y el objeto en sí se mata (destruido o entregado al recolector de basura ) cuando su cardinalidad llega a cero. Los lenguajes de programación de bajo nivel (como C ) permiten al programador controlar explícitamente si se usa la semántica de puntero o la semántica de copia.
Operación sustituciónMuchos idiomas brindan la capacidad de cambiar el significado de una asignación, ya sea a través del mecanismo de propiedad o mediante la sobrecarga del operador de asignación. La sustitución puede ser necesaria para realizar comprobaciones sobre la validez del valor asignado o cualquier otra operación adicional. La sobrecarga del operador de asignación se usa a menudo para proporcionar una "copia profunda", es decir, copiar valores en lugar de referencias, que se copian de forma predeterminada en muchos idiomas.
Dichos mecanismos permiten brindar comodidad en el trabajo, por lo que para un programador no hay diferencia entre usar un operador incorporado y uno sobrecargado. Por la misma razón, los problemas son posibles, ya que las acciones del operador sobrecargado pueden ser completamente diferentes de las acciones del operador predeterminado, y la llamada a la función no es obvia y puede confundirse fácilmente con una operación integrada.
Dado que el operador de asignación se usa ampliamente, los desarrolladores de lenguajes de programación están tratando de desarrollar nuevas construcciones para simplificar la escritura de operaciones típicas (para agregar el llamado " azúcar sintáctico " al lenguaje). Además, en los lenguajes de programación de bajo nivel, el criterio de inclusión suele ser la capacidad de compilar en un código ejecutable eficiente. [3] El lenguaje C es especialmente famoso por esta propiedad .
Una alternativa al operador simple es la capacidad de asignar el valor de una expresión a múltiples objetos . Por ejemplo, en PL/1 , el operador
SUMA TOTAL = 0simultáneamente asigna cero a las variables SUMy TOTAL. En Ada , la asignación también es una declaración, no una expresión, por lo que la notación para la asignación múltiple es:
SUMA, TOTAL: Entero := 0;Una tarea similar en Python tiene la siguiente sintaxis:
suma = total = 0A diferencia de PL/1, Ada y Python, donde la asignación múltiple se considera solo una notación abreviada, en C , Lisp y otros, esta sintaxis tiene una base estricta: el operador de asignación simplemente devuelve el valor que se le asignó (ver arriba). Así que el último ejemplo es en realidad:
suma = (total = 0)Una línea como esta funcionará en C (si agrega un punto y coma al final), pero provocará un error en Python.
Algunos lenguajes, como Ruby y Python , admiten una sintaxis de asignación extendida llamada asignación paralela:
un , segundo = 1 , 11Se cree que tal asignación se realiza simultáneamente y en paralelo , lo que permite implementar brevemente, utilizando esta construcción, la operación de intercambiar los valores de dos variables.
Escritura usando asignación paralela | Asignación "tradicional": requiere una variable adicional y tres operaciones | Asignación "económica": no requiere una variable adicional, pero también contiene tres operaciones | Asignación aún más "económica": no requiere una variable adicional, funciona con operaciones de bits |
---|---|---|---|
un, segundo = segundo, un | t = un un = segundo b=t | una = una + segundo segundo = un - segundo a = a - b | un ^ = segundo segundo ^ = un un ^ = segundo |
La penúltima opción aritmética no es segura en lenguajes de programación o plataformas de hardware que verifican desbordamientos aritméticos .
La última opción solo funciona con tipos que admiten operaciones bit a bit (por ejemplo, el doublecompilador de C# no le permitirá intercambiar valores de variables de esta manera).
Algunos lenguajes (como PHP ) tienen construcciones para simular la asignación en paralelo:
lista ( $a , $b ) = matriz ( $b , $a );Algunos lenguajes de programación, como C++ , permiten objetivos condicionales en declaraciones de asignación. Por ejemplo, la expresión:
( bandera ? cuenta1 : cuenta2 ) = 0 ;asignará un valor a la 0variable count1si , y si . flag==truecount2flag==false
Otra variante de asignación condicional ( Ruby ):
un ||= 10Esta construcción asigna un avalor a una variable solo si el valor aún no ha sido asignado o es igual a false.
El operador de asignación compuesto le permite abreviar una forma de asignación de uso común. Con este método, puede acortar la notación de una asignación que usa la variable de destino como el primer operando en el lado derecho de la expresión, por ejemplo:
una = una + segundoLa sintaxis del operador de asignación compuesto de C es la unión del operador binario deseado y el =. Por ejemplo, las siguientes entradas son equivalentes
sum += value; | sum = sum + value; |
Los lenguajes de programación que admiten operadores compuestos ( C++ , C# , Python , Java , etc.) suelen tener versiones para la mayoría de los operadores binarios de esos lenguajes ( +=, -=, &=etc.).
En los lenguajes de la familia C , existen cuatro operadores aritméticos unarios (es decir, que toman un argumento) para incrementar y decrementar números en uno: dos operadores “ ” y dos operadores “ ”. Los operadores se pueden escribir antes del operando (prefijo) o después (postfijo o sufijo). Los operadores de prefijo y posfijo difieren en el orden de evaluación. Los operadores de prefijos cambian un número por uno y devuelven el número cambiado. Los operadores de sufijo almacenan un número en una variable temporal, modifican el número original y devuelven el valor de la variable temporal. ++--
Un ejemplo de uso del operador : ++
Incrementar el valor de una variable en uno | notación equivalente |
---|---|
count ++; | count = count + 1; |
Aunque no parece una tarea, lo es. El resultado de ejecutar la declaración anterior es el mismo que el resultado de ejecutar la asignación.
Los operadores " " se denominan operadores de incremento y los operadores " " se denominan operadores de decremento. Los operadores se utilizan a menudo en el lenguaje C cuando se trata de punteros e índices de matriz . ++--
El funcionamiento de las computadoras modernas consiste en leer datos de la memoria o dispositivo en registros, realizar operaciones en esos datos y escribir en la memoria o dispositivo. La operación principal aquí es la transferencia de datos (de registros a memoria, de memoria a registro, de registro a registro). En consecuencia, se expresa directamente por las instrucciones de los procesadores modernos . Entonces, para la arquitectura x86 (todos los comandos a continuación también se aplican a esta arquitectura), esta es una operación movy sus variedades para enviar datos de varios tamaños. La operación de asignación (transferencia de datos de una celda de memoria a otra) se implementa prácticamente directamente con este comando. En términos generales, se requieren dos instrucciones para realizar una transferencia de datos en la memoria: un movimiento de memoria a registro y un movimiento de registro a memoria, pero con optimizaciones, la cantidad de instrucciones se puede reducir en la mayoría de los casos.
movl -4(%ebp), %eax instrucciones para la asignación |