Articulo de referencia

Tarea (informática)

En programación informática , una instrucción de asignación establece o restablece el valor almacenado en la(s) ubicación(es) de almacenamiento indicadas por el nombre de una va...

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

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

Las asignaciones suelen permitir que una variable tome diferentes valores en distintos momentos de su ciclo de vida y ámbito . Sin embargo, algunos lenguajes (principalmente los estrictamente funcionales ) no permiten este tipo de reasignación "destructiva", ya que podría implicar cambios de estado no local. El objetivo es garantizar la transparencia referencial , es decir, funciones que no dependen del estado de alguna variable, pero que producen los mismos resultados para un conjunto dado de parámetros de entrada en cualquier momento. Los programas modernos en otros lenguajes también suelen utilizar estrategias similares, aunque menos estrictas y solo en ciertas 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 la programación imperativa en el que se asocian diferentes valores a un nombre de variable particular a medida que transcurre el tiempo. [ 1 ] El programa, en este modelo, opera cambiando su estado mediante sucesivas sentencias de asignación. [ 2 ] [ 3 ] Las primitivas de los lenguajes de programación imperativos se basan en la asignación para realizar la iteración . [ 4 ] En el nivel más bajo, la asignación se implementa mediante operaciones de máquina como MOVEo STORE. [ 2 ] [ 4 ]

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

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

Ejemplo: Suponiendo que ase trata de una variable numérica, la asignación significa que el contenido de la variable se duplica después de la ejecución de la instrucción.a := 2*aa

Un ejemplo de segmento de código C :

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

En este ejemplo, la variable xse declara primero como un entero y luego se le asigna el valor 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 le reasigna el valor 23. Finalmente, yse le asigna el valor 32.4.

Para una operación de asignación, es necesario que el valor expressionesté bien definido (es un rvalue válido ) y que variablerepresente una entidad modificable (es un lvalue modificable (no constante ) válido ). En algunos lenguajes, generalmente dinámicos , no es necesario declarar una variable antes de asignarle un valor. En dichos lenguajes, una variable se declara automáticamente la primera vez que se le asigna un valor, y el ámbito en el que se declara varía según el lenguaje.

Asignación única

Cualquier asignación que cambie un valor existente (por ejemplo, ) no está permitida en lenguajes puramente funcionales . [ 4 ] En programación funcional , se desaconseja la asignación en favor de la asignación única, más comúnmente conocida como inicialización . La asignación única es un ejemplo de enlace de nombre y difiere 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.x := x + 1

Una evaluación de una expresión no tiene un efecto secundario si no cambia un estado observable de la máquina, [ 5 ] aparte de producir el resultado, y siempre produce el mismo valor para la misma entrada. [ 4 ] La asignación imperativa puede introducir efectos secundarios al destruir y hacer que el valor anterior no esté disponible mientras lo sustituye por uno nuevo, [ 6 ] y por esa razón se la denomina asignación destructiva en LISP y programación funcional , similar a la actualización destructiva .

La asignación simple es la única forma de asignación disponible en lenguajes puramente funcionales, como Haskell , que no tienen variables en el sentido de los lenguajes de programación imperativos [ 4 ] , sino valores constantes con nombre, posiblemente de naturaleza compuesta, cuyos elementos se definen progresivamente bajo demanda , para los lenguajes perezosos . Los lenguajes puramente funcionales pueden brindar la oportunidad de realizar cálculos en paralelo , evitando el cuello de botella de von Neumann de la ejecución secuencial paso a paso, ya que los valores son independientes entre sí. [ 7 ]

Los lenguajes funcionales impuros proporcionan tanto asignación simple como asignación verdadera (aunque la asignación verdadera se usa con menos frecuencia que en los lenguajes de programación imperativos). Por ejemplo, en Scheme, tanto la asignación simple (con let) como la asignación verdadera (con set!) se pueden usar en todas las variables, y se proporcionan primitivas especializadas para la actualización destructiva dentro de listas, vectores, cadenas, etc. En OCaml, solo se permite la asignación simple para variables, a través de la sintaxis; sin embargo, la actualización destructiva se puede usar en elementos de matrices y cadenas con un operador separado, así como en campos de registros y objetos que han sido declarados explícitamente mutables (es decir, capaces de ser cambiados después de su declaración inicial) por el programador.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, a diferencia de 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 Prolog sin retroceso puede considerarse asignación única explícita , explícita en el sentido de que sus variables (con nombre) pueden estar en un estado explícitamente no asignado, o establecerse exactamente una vez. En Haskell, por el contrario, no puede haber variables no asignadas, y cada variable puede pensarse como establecida implícitamente, cuando se crea, a su valor (o más bien a un objeto computacional que producirá su valor bajo demanda ).

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 instrucción de asignación devuelve el valor asignado, lo que permite modismos como x = y = a, en el que la instrucción de asignación y = adevuelve el valor de a, que luego se asigna a x. En una instrucción como , el valor de retorno de una función se utiliza para controlar un bucle mientras se asigna ese mismo valor a una variable.while((ch=getchar())!=EOF){}

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

En Haskell , [ 8 ] no existe la asignación de variables; pero las operaciones similares a la asignación (como asignar a un campo de un array o a un campo de una estructura de datos mutable) suelen evaluarse al tipo de unidad , que se representa como (). Este tipo tiene un único valor posible, por lo que no contiene información. Normalmente es el tipo de una 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, suelen tener una sintaxis especial para respaldarlos. Estas sintaxis son principalmente azúcar sintáctico para reducir la redundancia en el código fuente, pero también ayudan a quienes leen el código a comprender la intención del programador y proporcionan al compilador una pista para posibles optimizaciones.

Tarea ampliada

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 lo que a = 2*aen su lugar se puede escribir como a *= 2. [ 3 ] Más allá del azúcar sintáctico, esto ayuda a la tarea del compilador al dejar claro que es posible la modificación in situ de la variable a.

Asignación encadenada

Una instrucció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 asignaciones encadenadas. Las asignaciones encadenadas son equivalentes a una secuencia de asignaciones, pero la estrategia de evaluación difiere entre lenguajes. Para asignaciones encadenadas simples, como la inicialización de múltiples variables, la estrategia de evaluación no importa; sin embargo, si los objetivos (valores l) de la asignación están conectados de alguna manera, la estrategia de evaluación afecta el resultado.

En algunos lenguajes de programación ( como C ), se admiten asignaciones encadenadas porque las asignaciones son expresiones y tienen valores. En este caso, la asignación encadenada se puede implementar mediante una asignación asociativa derecha , y las asignaciones se realizan 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 declarando el tipo de retorno apropiado para el operador de asignación.

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

Asignación paralela

Algunos lenguajes de programación, como APL , Common Lisp , [ 10 ] Go , [ 11 ] JavaScript (desde la versión 1.7) [ 12 ] , Julia , PHP , Maple , Lua , occam 2 , [ 13 ] Perl , [ 14 ] Python , [ 15 ] REBOL , Ruby , [ 16 ] y PowerShell permiten asignar varias variables en paralelo, con una sintaxis como:

a, b := 0, 1

que asigna simultáneamente 0 a ay 1 a b. Esto se conoce comúnmente como asignación paralela ; se introdujo en CPL en 1963, bajo el nombre de asignación simultánea , [ 17 ] y a veces se denomina asignación múltiple , aunque esto resulta 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 característica se denomina desempaquetado [ 18 ] o asignación desestructurada : [ 19 ]

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

La lista se desempaquetará de manera que se asigne 0 a ay 1 a b. Además,

a, b := b, a

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

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

ya que deja tanto como con el valor original de .a := b; b := aabb

Algunos lenguajes, como Go , F# y Python , combinan la asignación paralela, las tuplas y el 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 () -> tupla [ int , int ]: return 1 , 2a : int b : int a , b = f ()

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

// Sintaxis válida de C# o Rust ( a , b ) = ( b , a );
// C# tupla return ( string , int ) f () => ( "foo" , 1 ); var ( a , b ) = f ();
// Devuelve una tupla de Rust let f : fn () -> ( & str , i32 ) = || ( "foo" , 1 ); let ( a , b ): ( & str , i32 ) = f ();

Esto ofrece una alternativa al uso de parámetros de salida para devolver múltiples valores desde una función. Esta técnica se remonta a CLU (1974), y CLU contribuyó a popularizar la asignación paralela en general.

C# permite además la asignación de deconstrucción generalizada con implementación definida por la expresión del lado derecho, ya que el compilador busca un método de instancia o extensiónDeconstruct apropiado en la expresión, que debe tener parámetros de salida para las variables a las que se asigna. [ 20 ] Por ejemplo, un método de este tipo que daría a la clase 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 coma es similar a la asignación paralela al permitir que ocurran múltiples asignaciones dentro de una sola instrucción, escribiendo a = 1, b = 2en lugar de a, b = 1, 2. Esto se usa principalmente en bucles for y se reemplaza por la asignación paralela en otros lenguajes como Go. [ 21 ] 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 concurrentemente, usando 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 frecuentemente criticado, debido a su conflicto con el signo igual como comparador de igualdad. Esto genera confusión tanto en los principiantes al escribir código como en los programadores experimentados al leerlo. El uso del signo igual para la asignación se remonta al lenguaje Superplan de Heinz Rutishauser , diseñado entre 1949 y 1951, y fue particularmente popularizado por Fortran.

Un ejemplo notorio de mala idea fue la elección del signo igual para denotar asignación. Se remonta a Fortran en 1957 [ a ] y ha sido copiado ciegamente por ejércitos de diseñadores de lenguajes. ¿Por qué es una mala idea? Porque derroca una tradición centenaria de permitir que "=" denote una comparación de igualdad, un predicado que es verdadero o falso. Pero Fortran lo convirtió en una asignación, la imposición de la igualdad. En este caso, los operandos están en desventaja: el operando izquierdo (una variable) debe ser igual al operando derecho (una expresión). x = y no significa lo mismo que y = x. [ 22 ]

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

Los programadores principiantes a veces confunden la asignación con el operador relacional de igualdad, ya que "=" significa igualdad en matemáticas y se usa para la asignación en muchos lenguajes. Pero la asignación modifica 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 utiliza un único signo de igual ( "=") tanto para el operador de asignación como para el operador relacional de igualdad, y el contexto determina a cuál se refiere. Otros lenguajes utilizan símbolos diferentes para ambos operadores. [ 23 ] Por ejemplo:

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

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

Notación

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

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

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

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

Algunos lenguajes orientados a expresiones, como Lisp [ 35 ] [ 36 ] y Tcl, utilizan uniformemente la sintaxis de prefijo (o posfijo) para todas las instrucciones, incluida la asignación.

Véase también

Notas

  1. El uso de es=anterior a Fortran, aunque fue Fortran quien lo popularizó.

Referencias

  1. 1 2 "2cs24 Declarativo" . www.csc.liv.ac.uk. Archivado del original el 24 de abril de 2006. Recuperado el 20 de abril de 2018 .
  2. 1 2 3 "Programación imperativa" . uah.edu . Archivado del original el 4 de marzo de 2016. Recuperado el 20 de abril de 2018 .
  3. 1 2 3 Ruediger-Marcus Flaig (2008). Programación bioinformática en Python: un curso práctico para principiantes . Wiley-VCH. pp. 98–99 . ISBN  978-3-527-32094-3. Consultado el 25 de diciembre de 2010 .
  4. 1 2 3 4 5 Cruzando fronteras: Explorando la programación funcional con Haskell Archivado el 19 de noviembre de 2010 en Wayback Machine , por Bruce Tate
  5. Mitchell, John C. (2003). Conceptos en lenguajes de programación . Cambridge University Press. pág. 23. ISBN  978-0-521-78098-8Consultado el 3 de enero de 2011 .
  6. "Lenguajes de programación imperativos (IPL)" (PDF) . gwu.edu . Archivado del original (PDF) el 16 de julio de 2011. Consultado el 20 de abril de 2018 .
  7. John C. Mitchell (2003). Conceptos en lenguajes de programación . Cambridge University Press. págs. 81–82 . ISBN  978-0-521-78098-8Consultado el 3 de enero de 2011 .
  8. Hudak, Paul (2000). The Haskell School of Expression: Learning Functional Programming Through Multimedia . Cambridge: Cambridge University Press. ISBN 0-521-64408-9.
  9. "7. Instrucciones simples — Documentación de Python 3.6.5" . docs.python.org . Consultado el 20 de abril de 2018 .
  10. "CLHS: Macro SETF, PSETF" . Hiperespecificación de Common Lisp . LispWorks . Consultado el 23 de abril de 2019 .
  11. Especificación del lenguaje de programación Go: Asignaciones
  12. Fitzgerald, Nick; Orendorff, Jason. "ES6 en profundidad: Desestructuración" . Mozilla Hacks . Consultado el 3 de diciembre de 2025 .
  13. INMOS Limited, ed. (1988). Manual de referencia de Occam 2. Nueva Jersey: Prentice Hall. ISBN 0-13-629312-3.
  14. Wall, Larry ; Christiansen, Tom; Schwartz, Randal C. (1996). Lenguaje de programación Perl (2.ª ed.). Cambridge: O'Reilly. ISBN  1-56592-149-6.
  15. Lutz, Mark (2001). Lenguaje de programación Python (2.ª ed.). Sebastopol: O'Reilly. ISBN  0-596-00085-5.
  16. Thomas, David; Hunt, Andrew (2001). Programming Ruby: The Pragmatic Programmer's Guide . Upper Saddle River: Addison Wesley. ISBN 0-201-71089-7.
  17. DW Barron et al. , "Las principales características de CPL", Computer Journal 6 :2:140 (1963). Texto completo (suscripción)
  18. "PEP 3132 -- Desempaquetado iterable extendido" . legacy.python.org . Consultado el 20 de abril de 2018 .
  19. "Desestructuración de la asignación" . MDN Web Docs . Consultado el 20 de abril de 2018 .
  20. "Descomposición de tuplas y otros tipos" . Microsoft Docs . Microsoft . Consultado el 29 de agosto de 2019 .
  21. Go efectivo : para , "Finalmente, Go no tiene operador coma y ++ y -- son sentencias, no expresiones. Por lo tanto, si quieres ejecutar varias variables en un bucle for, debes usar la asignación paralela (aunque eso excluye ++ y --)."
  22. Niklaus Wirth. "Buenas ideas, a través del espejo" . CiteSeerX 10.1.1.88.8309 . 
  23. "Lenguaje de programación C++. Conceptos básicos" . ntu.edu.sg. 1 de junio de 2013. Consultado el 21 de junio de 2024 .
  24. Corbet (6 de noviembre de 2003). "Un intento de abrir una puerta trasera en el kernel" . lwn.net . Consultado el 21 de junio de 2024 .
  25. "Opciones del analizador estático (usando la colección de compiladores GNU (GCC))" . gcc.gnu.org . Consultado el 21 de junio de 2024 .
  26. Deitel, Paul; Deitel, Harvey (25-10-2022). "Instrucciones de control de C++, parte 2" . Domyassignments . Recuperado el 21-06-2024 .
  27. Moore, Lawrie (1980). Fundamentos de programación con Pascal . Nueva York: John Wiley & Sons. ISBN 0-470-26939-1.
  28. Meyer, Bertrand (1992). Eiffel the Language . Hemel Hempstead: Prentice Hall International (Reino Unido). ISBN 0-13-247925-7.
  29. Wiener, Richard (1996). Una introducción a la informática orientada a objetos con Eiffel . Upper Saddle River, Nueva Jersey: Prentice Hall. ISBN 0-13-183872-5.
  30. Feinberg, Neal; Keene, Sonya E.; Mathews, Robert O.; Withington, P. Tucker (1997). Dylan Programming . Massachusetts: Addison Wesley. ISBN 0-201-47976-1.
  31. "PEP 572 Expresiones de asignación" . python.org . 28 de febrero de 2018. Consultado el 4 de marzo de 2020 .
  32. "Especificación del lenguaje de programación Go - El lenguaje de programación Go" . golang.org . Consultado el 20 de abril de 2018 .
  33. Ullman, Jeffrey D. (1998). Elementos de programación ML: Edición ML97 . Englewood Cliffs, Nueva Jersey: Prentice Hall. ISBN 0-13-790387-1.
  34. Iverson, Kenneth E. (1962). Un lenguaje de programación . John Wiley and Sons. ISBN 0-471-43014-5Archivado del original el 4 de junio de 2009. Consultado el 9 de mayo de 2010 .{{cite book}}: Incompatibilidad de ISBN/Fecha ( ayuda )
  35. Graham, Paul (1996). ANSI Common Lisp . Nueva Jersey: Prentice Hall. ISBN 0-13-370875-6.
  36. Steele, Guy L. (1990). Common Lisp: El lenguaje . Lexington: Digital Press. ISBN 1-55558-041-6.
  37. Dybvig, R. Kent (1996). El lenguaje de programación Scheme: ANSI Scheme . Nueva Jersey: Prentice Hall. ISBN 0-13-454646-6.
  38. Smith, Jerry D. (1988). Introducción a Scheme . Nueva Jersey: Prentice Hall. ISBN 0-13-496712-7.
  39. Abelson, Harold; Sussman, Gerald Jay; Sussman, Julie (1996). Estructura e interpretación de programas informáticos . Nueva Jersey: McGraw-Hill. ISBN 0-07-000484-6.