stringtranslate.com

Declaración de devolución

En programación de computadoras , una declaración de retorno hace que la ejecución abandone la subrutina actual y se reanude en el punto del código inmediatamente después de la instrucción que llamó a la subrutina, conocido como su dirección de retorno . La dirección de retorno la guarda la rutina de llamada, hoy generalmente en la pila de llamadas del proceso o en un registro . Las declaraciones de retorno en muchos lenguajes de programación permiten que una función especifique un valor de retorno que se devolverá al código que llamó a la función.

Descripción general

En C y C++ , (donde es una expresión ) es una declaración que le dice a una función que devuelva la ejecución del programa a la función que llama e informa el valor de . Si una función tiene el tipo de retorno void , la declaración de retorno se puede usar sin un valor, en cuyo caso el programa simplemente sale de la función actual y regresa a la que llama. [1] [2] Se utiliza una sintaxis similar en otros lenguajes, incluidos Modula-2 [3] y Python . [4]return exp;expexp

En Pascal no hay declaración de devolución. Las funciones o procedimientos regresan automáticamente al llegar a su última declaración. El valor de retorno de una función se proporciona dentro de la función realizando una asignación a un identificador con el mismo nombre que la función. [5] Sin embargo, algunas versiones de Pascal proporcionan una función especial que se puede utilizar para devolver un valor inmediatamente desde una función o, sin parámetros, para devolver inmediatamente desde un procedimiento. [6]Exit(exp);

Al igual que Pascal, FORTRAN II , Fortran 66 , Fortran 77 y versiones posteriores de Fortran especifican valores de retorno mediante una asignación al nombre de la función, pero también tienen una declaración de retorno; esa declaración no especifica un valor de retorno y, para una función, hace que se devuelva el valor asignado al nombre de la función. [5] [7] [8]

En algunos otros idiomas se utiliza un parámetro de salida definido por el usuario en lugar del identificador de función. [9]

Oberon ( Oberon-07 ) tiene una cláusula de devolución en lugar de una declaración de devolución. La cláusula de devolución se coloca después de la última declaración del órgano del procedimiento. [10]

Algunos lenguajes de programación orientados a expresiones , como Lisp , Perl y Ruby , permiten al programador omitir una declaración de retorno explícita, especificando en su lugar que la última expresión evaluada es el valor de retorno de la subrutina. En otros casos, se devuelve un valor nulo si no hay una declaración de retorno explícita: en Python , el valor Nonese devuelve cuando se omite la declaración de retorno, [4] mientras que en JavaScript undefinedse devuelve el valor.

En Windows PowerShell, todas las expresiones evaluadas que no se capturan (por ejemplo, asignadas a una variable, convertidas en void o canalizadas a $null ) se devuelven desde la subrutina como elementos de una matriz o como un único objeto en el caso de que solo haya un objeto. no ha sido capturado.

En Perl, el valor o valores de retorno de una subrutina pueden depender del contexto en el que se llamó. La distinción más fundamental es un contexto escalar donde el código de llamada espera un valor, un contexto de lista donde el código de llamada espera una lista de valores y un contexto vacío donde el código de llamada no espera ningún valor de retorno. Una subrutina puede verificar el contexto usando la wantarrayfunción. Se utiliza una sintaxis especial de retorno sin argumentos para devolver un valor indefinido en un contexto escalar y una lista vacía en un contexto de lista. El contexto escalar se puede dividir en contextos booleanos , numéricos, de cadena y de varios tipos de referencia . Además, se puede devolver un objeto sensible al contexto utilizando una secuencia de retorno contextual, con evaluación diferida de valores escalares.

Muchos sistemas operativos permiten que un programa devuelva un resultado (separado de la salida normal ) cuando finaliza su proceso; estos valores se refieren a estados de salida . La cantidad de información que se puede transmitir de esta manera es bastante limitada y, en la práctica, a menudo se limita a señalar el éxito o el fracaso. Desde dentro del programa, este retorno generalmente se logra llamando a Exit (llamada al sistema) (común incluso en C, donde está disponible el mecanismo alternativo de regresar desde la función principal ).

Sintaxis

Las declaraciones de devolución vienen en muchas formas. Las siguientes sintaxis son las más comunes:

En algunos lenguajes ensambladores , por ejemplo el de MOS Technology 6502 , se utiliza el mnemotécnico "RTS" (ReTurn from Subroutine).

Múltiples declaraciones de devolución

Los lenguajes con una declaración de retorno explícita crean la posibilidad de múltiples declaraciones de retorno en la misma función. Si eso es algo bueno o no es controvertido.

Los firmes partidarios de la programación estructurada se aseguran de que cada función tenga una única entrada y una única salida (SESE). Por lo tanto, se ha argumentado [14] que se debe evitar el uso de la declaración return explícita excepto al final textual de una subrutina, considerando que, cuando se usa para "regresar temprano", puede sufrir el mismo tipo de problemas. que surgen para la declaración GOTO . Por el contrario, se puede argumentar que vale la pena usar la declaración return cuando la alternativa es un código más complicado, como un anidamiento más profundo, lo que perjudica la legibilidad.

En su libro de texto de 2004, David Watt escribe que "los flujos de control de múltiples salidas y de entrada única suelen ser deseables". Utilizando la noción marco de secuenciador de Tennent , Watt describe uniformemente las construcciones de flujo de control que se encuentran en los lenguajes de programación contemporáneos e intenta explicar por qué ciertos tipos de secuenciadores son preferibles a otros en el contexto de flujos de control de salidas múltiples. Watt escribe que los gotos (secuenciadores de salto) sin restricciones son malos porque el destino del salto no se explica por sí mismo para el lector de un programa hasta que el lector encuentra y examina la etiqueta o dirección real que es el objetivo del salto. Por el contrario, Watt sostiene que la intención conceptual de un secuenciador de retorno queda clara a partir de su propio contexto, sin tener que examinar su destino. Además, Watt escribe que una clase de secuenciadores conocidos como secuenciadores de escape , definidos como "secuenciador que finaliza la ejecución de un comando o procedimiento que incluye texto", abarca tanto las interrupciones de los bucles (incluidas las interrupciones de varios niveles) como las declaraciones de retorno. Watt también señala que si bien los secuenciadores de salto (gotos) han estado algo restringidos en lenguajes como C, donde el objetivo debe ser un bloque interno o un bloque externo envolvente, esa restricción por sí sola no es suficiente para hacer que la intención de los gotos en C sea propia. -describir y así todavía pueden producir " código espagueti ". Watt también examina en qué se diferencian los secuenciadores de excepción de los secuenciadores de escape y salto; Para obtener más detalles sobre esto, consulte el artículo sobre programación estructurada. [15]

Según estudios empíricos citados por Eric S. Roberts , los estudiantes de programación tenían dificultades para formular soluciones correctas para varios problemas simples en un lenguaje como Pascal, que no permite múltiples puntos de salida. Para el problema de escribir una función para buscar linealmente un elemento en una matriz, un estudio de 1980 realizado por Henry Shapiro (citado por Roberts) encontró que usando solo las estructuras de control proporcionadas por Pascal, solo el 20% de los sujetos dieron la solución correcta. , mientras que ningún sujeto escribió código incorrecto para este problema si se le permitió escribir un retorno desde la mitad de un bucle. [dieciséis]

Otros, incluidos Kent Beck y Martin Fowler, argumentan que una o más cláusulas de protección (declaraciones de retorno de "salida anticipada" condicionales cerca del comienzo de una función) a menudo hacen que una función sea más fácil de leer que la alternativa. [17] [18] [19] [20]

El problema más común en la salida anticipada es que las declaraciones finales o de limpieza no se ejecutan; por ejemplo, la memoria asignada no se desasigna o los archivos abiertos no se cierran, lo que provoca fugas. Estos deben realizarse en cada sitio de devolución, ya que es frágil y puede provocar errores fácilmente. Por ejemplo, en un desarrollo posterior, un desarrollador podría pasar por alto una declaración de retorno y una acción que debería realizarse al final de una subrutina (por ejemplo, una declaración de seguimiento ) podría no realizarse en todos los casos. Los idiomas sin declaración de devolución, como el Pascal estándar, no tienen este problema. Algunos lenguajes, como C++ y Python, emplean conceptos que permiten que se realicen acciones automáticamente al regresar (o generar una excepción), lo que mitiga algunos de estos problemas; a menudo se conocen como "intentar/finalmente" o similares. Funcionalidades como estas cláusulas "finalmente" se pueden implementar mediante un paso al único punto de retorno de la subrutina. Una solución alternativa es utilizar el desenrollado normal de la pila (desasignación de variables) al salir de la función para desasignar recursos, como a través de destructores en variables locales, o mecanismos similares como la declaración "with" de Python.

Algunas implementaciones tempranas de lenguajes como el Pascal y C originales restringieron los tipos que una función puede devolver (por ejemplo, no admiten tipos de registros o estructuras ) para simplificar sus compiladores .

En Java (y lenguajes similares modelados a partir de él, como JavaScript ), es posible ejecutar código incluso después de la declaración return, porque el bloque finalmente de una estructura try-catch siempre se ejecuta. Entonces, si la declaración de retorno se coloca en algún lugar dentro de los bloques try o catch , se ejecutará el código finalmente (si se agrega). Incluso es posible alterar el valor de retorno de un tipo no primitivo (una propiedad de un objeto ya devuelto) porque la salida también ocurre después. [21]

Declaraciones de rendimiento

Las declaraciones de prima a devolución son declaraciones de rendimiento : donde una devolución provoca que finalice una subrutina , un rendimiento hace que se suspenda una corutina . La corrutina continuará posteriormente desde donde se suspendió si se vuelve a llamar. Las corrutinas son mucho más complicadas de implementar que las subrutinas y, por lo tanto, las declaraciones de rendimiento son menos comunes que las declaraciones de retorno, pero se encuentran en varios idiomas.

Secuencias de llamada/retorno

Son posibles varias secuencias de llamada/retorno según el conjunto de instrucciones del hardware, incluidas las siguientes:

  1. La CALLinstrucción envía la dirección de la siguiente instrucción a la pila y se ramifica a la dirección especificada. La RETURNinstrucción extrae la dirección de retorno de la pila al puntero de instrucción y la ejecución se reanuda en esa dirección. (Ejemplos: x86 , PDP-11 ) En arquitecturas como Motorola 96000 , el área de la pila se puede asignar en un espacio de direcciones separado, que se denomina 'Espacio de memoria de la pila', [22] distinto del espacio de direcciones de la memoria principal. [23] El NEC μPD7720 también cuenta con una pila con su propio espacio de direcciones separado. [24]
  2. La CALLinstrucción coloca la dirección de la siguiente instrucción en un registro y se ramifica a la dirección especificada. La RETURNsecuencia de instrucciones coloca la dirección de retorno del registro en el puntero de instrucción y la ejecución se reanuda en esa dirección. (Ejemplos: IBM System/360 y sucesores hasta z/Architecture , la mayoría de las arquitecturas RISC )
  3. La CALLinstrucción coloca la dirección de la siguiente (o actual ) instrucción en la ubicación de almacenamiento en la dirección de llamada y se ramifica a la dirección especificada+1. La RETURNsecuencia de instrucciones se bifurca a la dirección de retorno mediante un salto indirecto a la primera instrucción de la subrutina. (Ejemplos: IBM 1130 , SDS 9XX , PDP-8 )

Ver también

Notas

  1. ^ en el shell Bourne, solo se pueden devolver números enteros en el rango 0-255 [11]

Referencias

  1. ^ ab "Declaración de devolución (C)". Documentos de Microsoft . 25 de enero de 2023.
  2. ^ ab "Declaración de retorno (C++)". Documentos de Microsoft . 3 de agosto de 2021.
  3. ^ Gleaves, R. (2012). Módulo-2 para programadores Pascal. Saltador. pag. 71.ISBN _ 9781461385318.
  4. ^ abc Martelli, Alex (2006). Python en pocas palabras: una referencia rápida de escritorio (2ª ed.). Medios O'Reilly. pag. 73.ISBN _ 9781449379100.
  5. ^ ab Scott, Michael L. (2006). Pragmática del lenguaje de programación. Morgan Kaufman. pag. 432.ISBN _ 9780126339512.
  6. ^ Flandes, Harley (2012). Pascal científico. Saltador. pag. 35.ISBN _ 9781461224280.
  7. ^ ANSI x3.9-1966. FORTRAN estándar de EE. UU. (PDF) . Instituto Americano de Estándares Nacionales. pag. 14. Archivado desde el original (PDF) el 15 de mayo de 2011 . Consultado el 5 de mayo de 2010 .{{cite book}}: Mantenimiento CS1: nombres numéricos: lista de autores ( enlace )
  8. ^ ANSI x3.9-1978. Estándar Nacional Americano – Lenguaje de programación FORTRAN. Instituto Americano de Estándares Nacionales. 15.8 Declaración DEVOLUCIÓN. Archivado desde el original el 29 de octubre de 2013 . Consultado el 11 de diciembre de 2007 .{{cite book}}: Mantenimiento CS1: nombres numéricos: lista de autores ( enlace )
  9. ^ Sakkinen, Markku (marzo de 1989). "Cómo devolver mejor el valor de una función". Avisos ACM SIGPLAN . Asociación para Maquinaria de Computación. 24 (3): 55–56. doi : 10.1145/66083.66087 .
  10. ^ Wirth, Niklaus (3 de mayo de 2016). "10. Declaraciones de procedimiento". El lenguaje de programación Oberon (PDF) (Reporte). pag. 11.
  11. ^ "regresar: regresar desde una función o secuencia de comandos de puntos". Especificación única de UNIX .
  12. ^ "PHP: volver - Manual". Manual PHP . El grupo PHP . Consultado el 26 de marzo de 2013 .
  13. ^ "Regresar: Javascript". Referencia de Javascript de MDN . Red de desarrolladores de Mozilla . Consultado el 27 de marzo de 2013 .
  14. ^ "Notas de C++: declaración de retorno de función".
  15. ^ Vatio, David Anthony; Findlay, William (2004). Conceptos de diseño de lenguajes de programación . John Wiley e hijos. págs. 215-221. ISBN 978-0-470-85320-7.
  16. ^ Roberts, E. (marzo de 1995). "Salidas de bucle y programación estructurada: reapertura del debate". Boletín ACM SIGCSE . 27 (1): 268–272. doi : 10.1145/199691.199815 .
  17. ^ Martín Fowler; Kent Beck; Juan Brant; William Opdyke; Don Roberts (2012). Refactorización: mejora del diseño del código existente (Google eBook). Addison-Wesley. págs.237, 250. ISBN 9780133065268. ... mentalidad de un punto de salida ... No sigo la regla sobre un punto de salida de un método.
  18. ^ Kent Beck (2007). "7: Comportamiento". Patrones de implementación. Educación Pearson. apartado "Cláusula de Guarda". ISBN 9780132702553.
  19. ^ "Múltiples declaraciones de devolución". Prácticas de Java .
  20. ^ Fred Swartz. "Declaraciones de retorno y la fantasía de salida única". Archivado desde el original el 23 de febrero de 2020.
  21. ^ "El bloque finalmente". Los tutoriales de Java .
  22. ^ "MANUAL DEL USUARIO DEL PROCESADOR DE SEÑAL DIGITAL DE 32 BITS DSP96002" (PDF) . pag. 27(3 - ​​4) . Consultado el 24 de diciembre de 2023 .
  23. ^ "MANUAL DEL USUARIO DEL PROCESADOR DE SEÑAL DIGITAL DSP96002 DE 32 BITS" (PDF) . pag. 50(4 - 11) . Consultado el 24 de diciembre de 2023 .
  24. ^ "Procesador de señal digital μPD77C20A, 7720A, 77P20". pag. 4(3a-4) . Consultado el 25 de diciembre de 2023 .