stringtranslate.com

Tarea (informática)

En programación de computadoras , una declaración de asignación establece y/o restablece el valor almacenado en la ubicación de almacenamiento indicada 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 (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 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 = expr x := expr

Las asignaciones generalmente permiten que una variable mantenga 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 imponer transparencia referencial , es decir, funciones que no dependen del estado de algunas variables, pero que producen los mismos resultados para un conjunto determinado de entradas paramétricas en cualquier momento. Los programas modernos en otros lenguajes también suelen utilizar estrategias similares, aunque menos estrictas, y sólo en determinadas partes, con el fin de reducir la complejidad, normalmente en conjunto 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 de 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 utilizando declaraciones de asignación sucesivas. [2] [3] Los primitivos 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 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. [3] En consecuencia, la asignación depende del concepto de variables . En una tarea:

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 :

entero x = 10 ; flotar 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 ocurren en la misma declaración. En la segunda línea, yse declara sin cesió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 esté expressionbien definido (es un rvalue válido ) y que variablerepresente una entidad modificable (es un lvalue modificable (no constante ) válido ). 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 asigna, y el alcance en el que se declara varía según el idioma.

Asignación única

Cualquier asignación que cambie un valor existente (p. ej. x := x + 1) 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 vinculación de nombres 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.

Una evaluación de una expresión no tiene efectos secundarios 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 esa razón se conoce como 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 los lenguajes de programación imperativos [4] sino valores constantes nombrados posiblemente de naturaleza compuesta, con sus elementos definidos progresivamente en demanda , para las lenguas perezosas . 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 una asignación única como una asignación verdadera (aunque la asignación verdadera generalmente se usa con menos frecuencia que en los lenguajes de programación imperativos). Por ejemplo, en Scheme, se pueden usar tanto la asignación única (con let) como la asignación verdadera (con set!) en todas las variables, y se proporcionan primitivas especializadas para actualizaciones destructivas dentro de listas, vectores, cadenas, etc. En OCaml, solo se permite la asignación única para variables, mediante la sintaxis; sin embargo, la actualización destructiva se puede utilizar en elementos de matrices y cadenas con operador separado, así como en campos de registros y objetos que el programador ha declarado explícitamente mutables (es decir, que pueden cambiarse después de su declaración inicial).let name = value<-

Los lenguajes de programación funcionales que usan asignación única incluyen Clojure (para estructuras de datos, no vars), Erlang (acepta asignaciones múltiples 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 seguimiento puede considerarse de asignación única explícita , explícito en el sentido de que sus variables (nombradas) 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 se puede pensar que cada variable está implícitamente establecida, 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 declaración de asignación devuelve el valor asignado, lo que permite modismos como x = y = a, en los 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 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) generalmente se evalúan como el tipo de unidad , que se representa como (). Este tipo tiene sólo 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.

Variantes de cesión

Ciertos patrones de uso son muy comunes y, por lo tanto, suelen tener una sintaxis especial para respaldarlos. Se trata principalmente de azúcar sintáctico 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, 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 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 tareas encadenadas equivalen a una secuencia de tareas, pero la estrategia de evaluación difiere según el idioma. Para tareas encadenadas simples, como inicializar múltiples variables, la estrategia de evaluación no importa, pero si los objetivos (valores l) en la tarea están conectados de alguna manera, la estrategia de evaluación afecta el resultado.

En algunos lenguajes de programación ( C por ejemplo), se admiten asignaciones encadenadas porque las asignaciones son expresiones y tienen valores. En este caso, la asignación en cadena se puede implementar teniendo una asignación asociativa por la derecha , y las asignaciones se realizan de derecha a izquierda. Por ejemplo, i = arr[i] = f()equivale 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 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 objetivos 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 más a la izquierda, iy luego asigne el mismo resultado al siguiente objetivo, arr[i]usando el nuevo valor de i. [9] Esto es esencialmente equivalente a tmp = f(); i = tmp; arr[i] = tmpaunque no se produzca 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 sintaxis como:

a, b := 0, 1

que asigna simultáneamente 0 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 le llama 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 llama desempaquetado [17] o asignación de desestructuración : [18]

lista de variables : = {0, 1}a, b := lista

La lista se descomprimirá para asignar 0 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 := aa := bsegundo := t

ya que a := b; b := adeja ambos ay 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 entre paréntesis:

// Sintaxis válida de C# o Rust ( a , b ) = ( b , a );    
// retorno de tupla de C# ( cadena , int ) f () => ( "foo" , 1 ); var ( a , b ) = f ();         
// retorno de tupla de Rust let f = || ( "foo" , 1 ); sea ​​( 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# además permite la asignación de deconstrucción generalizada con 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 asigna. [19] Por ejemplo, uno de esos métodos que le daría a la clase el mismo comportamiento que el valor de retorno f()anterior sería

void Deconstruct ( fuera cadena a , fuera int b ) { a = "foo" ; segundo = 1 ; }              

En C y C++, el operador de coma es similar a la asignación paralela al permitir que se realicen múltiples asignaciones dentro de una sola declaración, escribiendo a = 1, b = 2en lugar de a, b = 1, 2. Esto se usa principalmente en bucles for y se reemplaza por 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 la nueva 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 de igualdad. Esto resulta tanto en confusión para los principiantes en la escritura de código como en confusión incluso para los programadores experimentados en la lectura de código. El uso de iguales 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 indicar una 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 permitir que "=" denote una comparación de igualdad, un predicado que es verdadero o falso. Pero Fortran lo interpretó como asignación, el cumplimiento de la igualdad. En este caso, los operandos están en condiciones desiguales: el operando izquierdo (una variable) debe igualarse al operando derecho (una expresión). x = y no significa lo mismo que y = x. [21]

—  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 utiliza para la asignación en muchos idiomas. 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 único 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 utilizan símbolos diferentes para los dos operadores. Por ejemplo:

La similitud entre los dos símbolos puede provocar errores si el programador olvida qué forma (" =", " ==", " :=") es apropiada, o escribe mal " =" cuando ==se pretendía " ". Este es un problema de programación común con lenguajes como C (incluido un famoso intento de abrir una puerta trasera al kernel de Linux), [22] 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 estar válidamente anidado 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 la thencláusula se ejecutará, lo que hará que el programa se comporte inesperadamente. 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 tarea de copia son el signo igual ( =) y 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.

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

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

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

Algunos lenguajes orientados a expresiones, como Lisp [31] [32] y Tcl, utilizan uniformemente la sintaxis de prefijo (o postfijo) para todas las declaraciones, incluida la asignación.

Ver también

Notas

  1. ^ El uso de =Fortran es anterior, aunque fue popularizado por Fortran.

Referencias

  1. ^ ab "Declarativo 2cs24". 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. págs. 98–99. ISBN 978-3-527-32094-3. Consultado el 25 de diciembre de 2010 .
  4. ^ abcde Cruzando fronteras: explore 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. Prensa de la Universidad de Cambridge. pag. 23.ISBN _ 978-0-521-78098-8. Consultado el 3 de enero de 2011 .
  6. ^ "Lenguajes de programación imperativos (IPL)" (PDF) . gwu.edu . Consultado el 20 de abril de 2018 .
  7. ^ John C. Mitchell (2003). Conceptos en lenguajes de programación. Prensa de la Universidad de Cambridge. págs. 81–82. ISBN 978-0-521-78098-8. Consultado el 3 de enero de 2011 .
  8. ^ Hudak, Paul (2000). La Escuela de Expresión Haskell: Aprendizaje de programación funcional a través de multimedia . Cambridge: Prensa de la Universidad de Cambridge. 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: macroSETF, PSETF". Hiperespecificación de Lisp común . 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. ^ Muro, Larry ; Christiansen, Tom; Schwartz, Randal C. (1996). Lenguaje de programación Perl (2 ed.). Cambridge: O'Reilly. ISBN 1-56592-149-6.
  14. ^ Lutz, Marcos (2001). Lenguaje de programación Python (2 ed.). Sebastopol: O´Reilly. ISBN 0-596-00085-5.
  15. ^ Tomás, David; Cazar, Andrés (2001). Programación Ruby: la guía pragmática del programador. Río Upper Saddle: Addison Wesley. ISBN 0-201-71089-7.
  16. ^ DW Barrón y otros. , "Las características principales de CPL", Computer Journal 6 :2:140 (1963). texto completo (suscripción)
  17. ^ "PEP 3132 - Desembalaje iterable extendido". legado.python.org . Consultado el 20 de abril de 2018 .
  18. ^ "Asignación de desestructuración". Documentos web de MDN . Consultado el 20 de abril de 2018 .
  19. ^ "Deconstruyendo tuplas y otros tipos". Documentos de Microsoft . Microsoft . Consultado el 29 de agosto de 2019 .
  20. ^ Go efectivo: para "Finalmente, Go no tiene operador de coma y ++ y -- son declaraciones, no expresiones. Por lo tanto, si desea ejecutar varias 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. ^ Corbet (6 de noviembre de 2003). "Un intento de hacer una puerta trasera al kernel".
  23. ^ Moore, Lawrie (1980). Fundamentos de programación con Pascal . Nueva York: John Wiley & Sons. ISBN 0-470-26939-1.
  24. ^ Meyer, Bertrand (1992). Eiffel el idioma . Hemel Hempstead: Prentice Hall International (Reino Unido). ISBN 0-13-247925-7.
  25. ^ Viena, Richard (1996). Una introducción a la informática orientada a objetos utilizando Eiffel . Upper Saddle River, Nueva Jersey: Prentice Hall. ISBN 0-13-183872-5.
  26. ^ Feinberg, Neal; Keene, Sonya E.; Mathews, Robert O.; Withington, P. Tucker (1997). Programación Dylan . Massachusetts: Addison Wesley. ISBN 0-201-47976-1.
  27. ^ "PEP 572 - Expresiones de asignación". python.org . 28 de febrero de 2018 . Consultado el 4 de marzo de 2020 .
  28. ^ "La especificación del lenguaje de programación Go: el lenguaje de programación Go". golang.org . Consultado el 20 de abril de 2018 .
  29. ^ Ullman, Jeffrey D. (1998). Elementos de programación ML: edición ML97 . Acantilados de Englewood, Nueva Jersey: Prentice Hall. ISBN 0-13-790387-1.
  30. ^ Iverson, Kenneth E. (1962). Un lenguaje de programación. John Wiley e hijos. ISBN 0-471-43014-5. Archivado desde el original el 4 de junio de 2009 . Consultado el 9 de mayo de 2010 .
  31. ^ Graham, Paul (1996). Ceceo común ANSI. Nueva Jersey: Prentice Hall. ISBN 0-13-370875-6.
  32. ^ Steele, Guy L. (1990). Lisp común: el lenguaje . Lexington: Prensa digital. ISBN 1-55558-041-6.
  33. ^ Dybvig, R. Kent (1996). El lenguaje de programación de esquemas: esquema ANSI . Nueva Jersey: Prentice Hall. ISBN 0-13-454646-6.
  34. ^ Smith, Jerry D. (1988). Introducción al esquema . Nueva Jersey: Prentice Hall. ISBN 0-13-496712-7.
  35. ^ 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.