¿En qué idioma (s) se establece el valor de retorno asignando el nombre de la función?
En esta pregunta de Stack Overflow, el código original cometió el error de usar el nombre de la función como variable y le asignó el valor de retorno. Un comentarista mencionó que una vez usó un lenguaje en el que esta era la forma en que devolvía el valor de las funciones. El comentario dice: "Sé que una vez usé un lenguaje en el que el valor de retorno de una función debía asignarse al nombre de la función. Es tan antiguo y obsoleto que ni siquiera puedo recordar qué idioma era".
Eso también me suena familiar, pero tampoco recuerdo qué idioma era.
¿Alguien tiene mejor memoria que nosotros y nos puede decir qué idioma es?
Respuestas
Pascal hace esto, no conozco otros. No sé si la práctica avanza con otros idiomas de Wirth.
Los lenguajes de la familia Visual Basic hacen exactamente esto. Esto incluye VBScript, VBA, Visual Basic y versiones anteriores. Creo que estos heredan la "función" de QBASIC. Por ejemplo
Public Function AddTwo(something as Integer)
AddTwo = something + 2
End Function
Fortran, seguro:
PROGRAM TRIANG
WRITE(UNIT=*,FMT=*)'Enter lengths of three sides:'
READ(UNIT=*,FMT=*) SIDEA, SIDEB, SIDEC
WRITE(UNIT=*,FMT=*)'Area is ', AREA3(SIDEA,SIDEB,SIDEC)
END
FUNCTION AREA3(A, B, C)
*Computes the area of a triangle from lengths of sides
S = (A + B + C)/2.0
AREA3 = SQRT(S * (S-A) * (S-B) * (S-C))
END
(de la Guía del programador profesional de Clive G. Page para Fortran77 ).
También se define de esa manera en el estándar Fortran ANSI X 3.9 1966 Fortran 66 .
Los primeros idiomas de este tipo que puedo encontrar son FORTRAN II y ALGOL 58, ambos publicados en el mismo año 1958; aunque podría decirse que también se puede incluir el FORTRAN original (1956).
Para FORTRAN, la primera página del capítulo del manual que cubre las funciones contiene este ejemplo (p. 27):
FUNCTION AVRG (ALIST, N)
DIMENSION ALIST (500)
SUM = ALIST (1)
DO 10 I=2, N
SUM = SUM + ALIST (I)
AVRG = SUM / FLOATF (N)
RETURN
END (2, 2, 2, 2, 2)
FORTRAN II también incluye otra sintaxis de función (p. 10), la definición de función de una sola línea, heredada de su predecesor:
FIRSTF(X) = A*X + B
No es difícil ver cómo la primera sintaxis es una extensión natural de la última, que a su vez proviene del uso matemático.
ALGOL 58 , de manera similar a FORTRAN, define ambas 'funciones' de una sola línea:
Una declaración de función declara que una expresión dada es función de algunas de sus variables. Por lo tanto, la declaración da (para ciertas funciones simples) la regla de cálculo para asignar valores a la función (cf. funciones ) siempre que esta función aparece en una expresión.
Forma: Δ ~ I n (I, I, ~, I): = E donde I son identificadores y E es una expresión que, entre sus constituyentes, puede contener variables simples nombradas por identificadores que aparecen entre paréntesis.
y 'procedimientos', equivalente a la definición actual de función (en lenguajes de programación imperativos / procedimentales, al menos). El valor de retorno se indica de la siguiente manera (p. 19):
Para cada procedimiento de salida individual I (P i ) enumerado en el encabezado, se debe asignar un valor dentro del procedimiento mediante una declaración de asignación “I: = E” donde I es el identificador que nombra ese procedimiento.
Estas sintaxis fueron retomadas más tarde por algunos dialectos de BASIC (en la forma de DEF FN
y posteriores FUNCTION
) y el descendiente Pascal de ALGOL: en los compiladores Pascal de Borland, la asignación al nombre de la función era la única sintaxis compatible antes de la introducción de la Result
variable en Delphi 1.0.
Probablemente sea Pascal a quien recordó el comentarista mencionado; algunas universidades todavía enseñan programación en él, y por lo general se apegan a la variedad estándar original, en lugar de dialectos extendidos modernos como Object Pascal. (Esto no es realmente parte de la pregunta, pero supongo que el malentendido del autor de la pregunta de StackOverflow también proviene de eso).
TL; DR:
Yo diría que lo más probable es que recuerdes PASCAL, ya que era bastante popular a principios de los 80, se usaba en cursos universitarios durante los 80 hasta los 90 y todavía tenía algo de beca allí después, sobre todo Delphi.
Algo de historia
La idea básica es que el nombre de la función no solo ya está reservado, por lo que no es necesario inventar nada diferente, y su uso es una declaración clara de que este es el resultado. También simplifica el diseño del compilador, ya que se puede asignar un elemento de datos dedicado dentro de la convención de llamada.
Básicamente hay dos líneas de herencia, FORTRAN y ALGOL.
Pues algunos de sus descendientes lo guardaron, como
- algunas variantes BÁSICAS de FORTRAN y
- Pascal y Modula de ALGOL.
Otros lo abandonaron, como el seguimiento de ALGOL.
- BCPL, que introdujo la
return()
sintaxis,
lo cual es bastante común hoy en día, ya que C lo tomó de BCPL.
Las ideas del lenguaje son como genes que saltan entre anfitriones. Por ejemplo, ADA, en muchos sentidos un nieto de ALGOL / PASCAL, también recurrió al uso de un return
elemento.
Granddaddy FORTRAN, a lo largo de los años, ha variado la forma en que devuelve los resultados de las funciones.
- Originalmente, el resultado de una función se asignaba al identificador de la función.
- con FORTRAN 90 se introdujo la definición explícita de un nombre de retorno en el encabezado de función.
Si bien esto es esencialmente azúcar sintáctico, presenta un cambio de estilo. El razonamiento aplicado fue que con construcciones recursivas como Foo = Foo(x-1)
se vería extraño. Pero supongo que eso depende de la interpretación.
Curiosamente aquí también es que FORTRAN II de 1958 introdujo una RETURN
declaración en su esfuerzo por agregar programación de procedimientos, pero su uso fue simplemente para devolver la ejecución a un llamador, el valor de retorno tenía que establecerse por separado.
Fortran ha utilizado esta sintaxis, desde la primera versión que tenía funciones hasta Fortran 2008 y más allá.
Sin embargo, Fortran 2008 tiene una opción (¿aún más confusa?) Donde puede declarar un nombre de variable diferente que se usa para devolver un valor de función. Por ejemplo
function xyz(argument) result(answer)
...
answer = 42
...
end function xyz
en lugar del estilo antiguo
...
xyz = 42
...
Algol 60 para uno.
Aquí están las palabras relevantes del Informe revisado sobre el lenguaje algorítmico Algol 60 .
5.4.4. Valores de designadores de funciones.
Para que una declaración de procedimiento defina el valor de un designador de función, debe ocurrir, dentro del cuerpo de declaración de procedimiento, una o más declaraciones de asignación explícitas con el identificador de procedimiento en una parte izquierda; al menos uno de estos debe ejecutarse, y el tipo asociado con el identificador de procedimiento debe declararse mediante la aparición de un declarador de tipo como el primer símbolo de la declaración de procedimiento. El último valor así asignado se utiliza para continuar la evaluación de la expresión en la que aparece el designador de función.
Cualquier aparición del identificador de procedimiento dentro del cuerpo del procedimiento que no sea en la parte izquierda de una instrucción de asignación denota la activación del procedimiento.
La última oración es significativa: muestra que el nombre del tipo procedimiento (función) no se trata "como" una variable dentro del cuerpo del procedimiento (función); más bien, es sólo una asignación que tiene un caso especial.
En Algol 60, una llamada a una función que no acepta argumentos no va seguida de paréntesis vacíos: por lo tanto en n := read
lugar de n := read()
.
La última oración también es famosa por ser la oración que incorporó procedimientos recursivos al idioma. Pero eso no está relacionado con esta respuesta.
BASIC es otro lenguaje con funciones donde algunos dialectos usaban asignación al nombre de la función para proporcionar el valor de retorno. Los primeros dialectos eran similares a las funciones de una sola línea de Fortran:
DEF FND(x) = x*x
Pero los dialectos posteriores permitieron variantes más complejas, similares a las funciones multilínea de Fortran :
DEF FNPeekWord& (A&)
FNPeekWord& = PEEK(A&) + 256& * PEEK(A& + 1)
END DEF
MATLAB / Octave también hace esto.
Es de 1984; así que no es tan viejo como algunos de los otros.
Probablemente imitaba a Fortran, ya que originalmente se concibió como una herramienta de alto nivel. Además de las bibliotecas de Fortran como Linpack y Eispack.
Creo que SNOBOL4 hizo esto. http://berstis.com/greenbook.pdf
El siguiente es un ejemplo de la definición y uso de una función para calcular factoriales de números:
DEFINE('FACT(N)') :(SKIPFCN) * Set value to 1 FACT FACT = 1 * Return 1 if N<2 * Return N*((N-1)!) with recursive call FACT = GT(N,1) FACT(N - 1) * N :(RETURN) SKIPFCN OUTPUT = '5 factorial is ' FACT(5)
http://berstis.com/s4ref/prim3e.htm
Verilog (1995/2001) también regresa por asignación a una variable implícita. SystemVerilog agregó la declaración "return" pero la asignación clásica todavía está disponible.
Haskell (desde 1990) también hace esto:
doubleMe x = x + x
define una función doubleMe
de un parámetro x
y le asigna el cuerpo de la función x+x
, vea el gran Aprenda usted a Haskell para un gran bien
Pascal es uno que utilicé personalmente que lo hace. Common Lisp es un poco-sorta-pero-no-realmente lo hace, ya que los valores de retorno son casi siempre implícitos (es decir, cada declaración tiene un valor, y el último valor en un bloque es el valor de retorno del bloque), por lo que rara vez se ve una declaración de rendimiento explícito, pero cuando tiene que devolver un valor y no puede utilizar la forma implícita, la manera de hacerlo es mediante el uso de la RETURN-FROM
[*] declaración, así: (return-from function-name value)
.
[*] También hay una RETURN
declaración, pero es una abreviatura de (return-from nil value)
, y no tendrá el efecto de hacer VALUE
el valor de la función en la que se ejecutó. Es una gran trampa para los novatos que vienen de C y sus descendientes.