stringtranslate.com

Tarea (informática)

En programación informática , una sentencia de asignación establece o restablece el valor almacenado en la(s) ubicación(es) 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 imperativa , la sentencia de asignación (o expresió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 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 utilizar en una expresión).x = expr x := expr

Las asignaciones suelen permitir que una variable contenga 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 alguna variable(s), pero que 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 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 programación imperativa en el que se asocian diferentes valores con un nombre de variable particular a medida que pasa el tiempo. [1] El programa, en dicho modelo, opera cambiando su estado mediante declaraciones de asignación sucesivas. [2] [3] Las primitivas de los lenguajes de programación imperativa se basan en la asignación para realizar la iteración . [4] En el nivel más bajo, la asignación se implementa utilizando operaciones de máquina como MOVEo STORE. [2] [4]

Las variables son contenedores de valores. Es posible introducir 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. [3] En consecuencia, la asignación depende del concepto de variables . En una asignación:

Ejemplo: Suponiendo 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 ; flotante y ; x = 23 ; y = 32.4f ;         

En este ejemplo, la variable xse declara primero como int y luego se le asigna el valor 10. Observe que la declaración y la asignación se producen 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 de expressionesté bien definido (sea un rvalue válido ) y que variablerepresente una entidad modificable (sea un lvalue modificable válido (no constante ) . En algunos lenguajes, normalmente los 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, 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, x := x + 1) no está permitida en lenguajes puramente funcionales . [4] En la programación funcional , la asignación se desaconseja 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 se diferencia de la asignación como se describe en este artículo en que solo se puede hacer una vez, generalmente cuando se crea la variable; no se permite ninguna reasignación posterior.

Una evaluación de una expresión no tiene un efecto secundario si no cambia un estado observable de la máquina, [5] además 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 al sustituirlo por uno nuevo, [6] y por ese motivo se la conoce como asignación destructiva en LISP y en programación funcional , de forma 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 nombrados posiblemente de naturaleza compuesta, con sus elementos definidos progresivamente a demanda , para los lenguajes perezosos . Los lenguajes puramente funcionales pueden proporcionar una oportunidad para que el cálculo se realice 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í. [7]

Los lenguajes funcionales impuros proporcionan tanto la asignación simple como la 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 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 las 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 (lo que significa que pueden cambiarse después de su declaración inicial) por el programador.let name = value<-

Los lenguajes de programación funcional que utilizan asignación única incluyen Clojure (para estructuras de datos, no variables), 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 valores), SISAL y Standard ML . El código Prolog sin retroceso puede considerarse de asignación única explícita , explícita en el sentido de que sus variables (nombradas) pueden estar en estado explícitamente no asignado o configurarse exactamente una vez. En Haskell, por el contrario, no puede haber variables sin asignar y se puede pensar que cada variable se configura implícitamente, cuando se crea, a su valor (o más bien a un objeto computacional que producirá su valor a pedido ).

Valor de una tarea

En algunos lenguajes de programación, una declaració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 sentencia de asignación devuelve el valor asignado, lo que permite expresiones como x = y = a, en la que la sentencia de asignación y = adevuelve el valor de a, que luego se asigna a x. En una sentencia 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, Scheme por ejemplo, el valor de retorno de una asignación no está definido y dichos modismos no son válidos.

En Haskell , [8] no hay asignación de variables; pero las operaciones similares a la asignación (como la asignación a un campo de una matriz o a un campo de una estructura de datos mutable) normalmente evalúan el tipo de unidad , que se representa como (). Este tipo tiene solo un 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 cesión

Ciertos patrones de uso son muy comunes y, por lo tanto, suelen tener una sintaxis especial que los respalda. Se trata principalmente de azúcar sintáctica para reducir la redundancia en el código fuente, pero también ayuda a los lectores del código a comprender la intención del programador y proporciona al compilador una pista para una posible optimización.

Tarea aumentada

El caso en el que el valor asignado depende de uno anterior es tan común que muchos lenguajes imperativos, especialmente C y la mayoría de sus descendientes, proporcionan operadores especiales llamados asignación aumentada , como *=, por lo que a = 2*apuede escribirse como a *= 2. [3] 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 en el lugar de la variable.

Asignación encadenada

Una declaración como w = x = y = zse denomina 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, 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 ( por ejemplo, C ), se admiten las asignaciones encadenadas 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 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 al declarar el tipo de retorno apropiado para el operador de asignación.

En Python , las instrucciones de asignación no son expresiones y, por lo tanto, no tienen un valor. En cambio, las asignaciones encadenadas son una serie de instrucciones con múltiples destinos para una sola expresión. Las asignaciones se ejecutan de izquierda a derecha, de modo que i = arr[i] = f()evalúa la expresión f(), luego asigna el resultado al destino más a la izquierda, iy luego asigna el mismo resultado al siguiente destino, arr[i], utilizando 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 1.7), PHP , Maple , Lua , occam 2 , [12] Perl , [13] Python , [14] REBOL , Ruby , [15] 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 más comúnmente como asignación paralela ; se introdujo en CPL en 1963, bajo el nombre de asignación simultánea , [16] y a veces se llama asignación múltiple , aunque esto es confuso cuando se usa con "asignación simple", 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 llama desempaquetado [17] o asignación desestructurante : [18]

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

La lista se descomprimirá de modo 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 debería escribirse para utilizar una variable temporal

var t := aa := bb := t

ya que a := b; b := adeja tanto acomo bcon el valor original de b.

Algunos lenguajes, como Go , F# 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 ():  devuelve  1 ,  2 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 );    
// Tupla de C# return ( cadena , int ) f () => ( "foo" , 1 ); var ( a , b ) = f ();         
// Tupla de Rust devuelve let f = || ( "foo" , 1 ); let ( a , b ) = f ();         

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

C# también permite la asignación de deconstrucción generalizada con la implementación definida por la expresión en el lado derecho, ya que el compilador busca una instancia o método de extensión Deconstruct apropiado en la expresión, que debe tener parámetros de salida para las variables a las que se asigna. [19] Por ejemplo, un método de este tipo que daría a la clase en la que aparece el mismo comportamiento que el valor de retorno de f()arriba sería

void Deconstruct ( out cadena 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 se produzcan múltiples asignaciones dentro de una sola declaración, escribiendo a = 1, b = 2en lugar de a, b = 1, 2. Esto se utiliza principalmente en bucles for y se reemplaza por la asignación paralela en otros lenguajes como Go. [20] 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 simultáneamente, 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 que genera con el signo igual como operador de comparación para la igualdad. Esto genera confusión tanto para los novatos a la hora de escribir código como para los programadores experimentados a la hora de 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 una mala idea fue la elección del signo igual para denotar la 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 derriba una tradición centenaria de dejar que “=” denote una comparación de igualdad, un predicado que es verdadero o falso. Pero Fortran lo hizo para que significara asignación, la imposición de la igualdad. En este caso, los operandos están en pie de igualdad: el operando izquierdo (una variable) debe hacerse igual al operando derecho (una expresión). x = y no significa lo mismo que y = x. [21]

—  Niklaus Wirth , Las 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 utiliza para la asignación en muchos lenguajes. Pero la asignación altera el valor de una variable, mientras que la prueba de igualdad prueba si dos expresiones tienen el mismo valor.

En algunos lenguajes, como BASIC , "="se utiliza un solo signo igual ( ) tanto para el operador de asignación como para el operador relacional de igualdad, y el contexto determina cuál de ellos se utiliza. Otros lenguajes utilizan símbolos diferentes para los dos operadores. [22] Por ejemplo:

La similitud entre los dos símbolos puede llevar a errores si el programador olvida qué forma (" =", " ==", " :=") es la apropiada, o escribe mal " =" cuando se pretendía " ==". Este es un problema de programación común con lenguajes como C (incluyendo un famoso intento de hacer una puerta trasera al kernel de Linux), [23] 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 ifdeclaració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 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. [24] [25]

Notación

Las dos representaciones más comunes para la asignación de copia son el signo igual ( =) y dos puntos-igual ( :=). 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 lenguaje 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 [34] [35] y Tcl, utilizan uniformemente la sintaxis de prefijo (o sufijo) para todas las declaraciones, incluida la asignación.

Véase también

Notas

  1. ^ Su uso =es anterior a Fortran, aunque fue popularizado por Fortran.

Referencias

  1. ^ ab "2cs24 Declarativo". www.csc.liv.ac.uk . Archivado desde el original el 24 de abril de 2006 . Consultado el 20 de abril de 2018 .
  2. ^ abc «Programación imperativa». uah.edu . Archivado desde el original el 4 de marzo de 2016. Consultado el 20 de abril de 2018 .
  3. ^ abc 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. Recuperado el 25 de diciembre de 2010 .
  4. ^ abcde Cruzando fronteras: explora 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-8. Recuperado el 3 de enero de 2011 .
  6. ^ "Imperative Programming Languages ​​(IPL)" (PDF) . gwu.edu . Archivado desde el original (PDF) el 2011-07-16 . Consultado el 20 de abril de 2018 .
  7. ^ John C. Mitchell (2003). Conceptos en lenguajes de programación. Cambridge University Press. pp. 81–82. ISBN 978-0-521-78098-8. Recuperado el 3 de enero de 2011 .
  8. ^ Hudak, Paul (2000). La escuela de expresión de Haskell: aprendizaje de programación funcional a través de multimedia . Cambridge: Cambridge University Press. ISBN 0-521-64408-9.
  9. ^ "7. Declaraciones simples — Documentación de Python 3.6.5". docs.python.org . Consultado el 20 de abril de 2018 .
  10. ^ "CLHS: Macro SETF, PSETF". Common Lisp Hyperspec . LispWorks . Consultado el 23 de abril de 2019 .
  11. ^ La especificación del lenguaje de programación Go: tareas
  12. ^ INMOS Limited, ed. (1988). Manual de referencia de Occam 2. Nueva Jersey: Prentice Hall. ISBN 0-13-629312-3.
  13. ^ Wall, Larry ; Christiansen, Tom; Schwartz, Randal C. (1996). Lenguaje de programación Perl (2.ª edición). Cambridge: O'Reilly. ISBN 1-56592-149-6.
  14. ^ Lutz, Mark (2001). Lenguaje de programación Python (2.ª edición). Sebastopol: O´Reilly. ISBN 0-596-00085-5.
  15. ^ Thomas, David; Hunt, Andrew (2001). Programación en Ruby: la guía del programador pragmático. Upper Saddle River: Addison Wesley. ISBN 0-201-71089-7.
  16. ^ DW Barron et al. , "Las principales características de CPL", Computer Journal 6 :2:140 (1963). texto completo (suscripción)
  17. ^ "PEP 3132 - Desempaquetado iterable extendido". legacy.python.org . Consultado el 20 de abril de 2018 .
  18. ^ "Asignación de desestructuración". MDN Web Docs . Consultado el 20 de abril de 2018 .
  19. ^ "Deconstrucción de tuplas y otros tipos". Microsoft Docs . Microsoft . Consultado el 29 de agosto de 2019 .
  20. ^ Go eficaz: para, "Finalmente, Go no tiene operador de coma y ++ y -- son declaraciones, no expresiones. Por lo tanto, si desea ejecutar múltiples variables en un for, debe usar la asignación paralela (aunque eso excluye ++ y --)."
  21. ^ Niklaus Wirth. "Buenas ideas a través del espejo". CiteSeerX 10.1.1.88.8309 . 
  22. ^ "Lenguaje de programación C++. Conceptos básicos". ntu.edu.sg . 2013-06-01 . Consultado el 2024-06-21 .
  23. ^ Corbet (6 de noviembre de 2003). "Un intento de crear una puerta trasera en el núcleo". lwn.net . Consultado el 21 de junio de 2024 .
  24. ^ "Opciones del analizador estático (utilizando la colección de compiladores GNU (GCC))". gcc.gnu.org . Consultado el 21 de junio de 2024 .
  25. ^ Deitel, Paul; Deitel, Harvey (25 de octubre de 2022). "Declaraciones de control de C++, parte 2". Domyassignments . Consultado el 21 de junio de 2024 .
  26. ^ Moore, Lawrie (1980). Fundamentos de programación con Pascal . Nueva York: John Wiley & Sons. ISBN 0-470-26939-1.
  27. ^ Meyer, Bertrand (1992). Eiffel the Language . Hemel Hempstead: Prentice Hall International (Reino Unido). ISBN 0-13-247925-7.
  28. ^ Wiener, Richard (1996). Introducción a la informática orientada a objetos con Eiffel . Upper Saddle River, Nueva Jersey: Prentice Hall. ISBN 0-13-183872-5.
  29. ^ Feinberg, Neal; Keene, Sonya E.; Mathews, Robert O.; Withington, P. Tucker (1997). Programación Dylan . Massachusetts: Addison Wesley. ISBN 0-201-47976-1.
  30. ^ "PEP 572 – Expresiones de asignación". python.org . 28 de febrero de 2018 . Consultado el 4 de marzo de 2020 .
  31. ^ "La especificación del lenguaje de programación Go - El lenguaje de programación Go". golang.org . Consultado el 20 de abril de 2018 .
  32. ^ Ullman, Jeffrey D. (1998). Elementos de programación de ML: edición ML97 . Englewood Cliffs, Nueva Jersey: Prentice Hall. ISBN 0-13-790387-1.
  33. ^ Iverson, Kenneth E. (1962). Un lenguaje de programación. John Wiley and Sons. ISBN 0-471-43014-5Archivado desde el original el 4 de junio de 2009. Consultado el 9 de mayo de 2010 .
  34. ^ Graham, Paul (1996). ANSI Common Lisp. Nueva Jersey: Prentice Hall. ISBN 0-13-370875-6.
  35. ^ Steele, Guy L. (1990). Common Lisp: el lenguaje . Lexington: Digital Press. ISBN 1-55558-041-6.
  36. ^ Dybvig, R. Kent (1996). El lenguaje de programación Scheme: ANSI Scheme . Nueva Jersey: Prentice Hall. ISBN 0-13-454646-6.
  37. ^ Smith, Jerry D. (1988). Introducción a Scheme . Nueva Jersey: Prentice Hall. ISBN 0-13-496712-7.
  38. ^ 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.