Em que idioma (s) o valor de retorno é definido pela atribuição ao nome da função?
Nesta questão do Stack Overflow, o código original cometeu o erro de usar o nome da função como uma variável e atribuiu o valor de retorno a ela. Um comentarista mencionou que certa vez usou uma linguagem em que era assim que você retornava o valor das funções. O comentário diz "Eu sei que uma vez usei uma linguagem em que o valor de retorno de uma função precisava ser atribuído ao nome da função. É tão antigo e obsoleto que nem consigo me lembrar de que idioma era."
Isso também me parece familiar, mas também não consigo me lembrar de que idioma era.
Alguém tem melhor memória do que nós e pode nos dizer que idioma é esse?
Respostas
Pascal faz isso, não conheço outros. Não sei se a prática avançou com outras línguas Wirth.
As linguagens da família Visual Basic fazem exatamente isso. Isso inclui VBScript, VBA, Visual Basic e anteriores. Eu acredito que eles herdam o "recurso" do QBASIC. Por exemplo
Public Function AddTwo(something as Integer)
AddTwo = something + 2
End Function
Fortran, com certeza:
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
(do Guia do Programador Profissional de Clive G. Page para Fortran77 ).
Também é definido dessa forma no padrão Fortran 66 do Fortran ANSI X 3.9 1966 .
As primeiras línguas que posso encontrar são FORTRAN II e ALGOL 58, ambos publicados no mesmo ano de 1958; embora o FORTRAN original (1956) também possa ser incluído.
Para FORTRAN, a primeira página do capítulo do manual que cobre as funções contém este exemplo (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 também inclui outra sintaxe de função (p. 10), a definição de função de linha única, herdada de seu prececessor:
FIRSTF(X) = A*X + B
Não é difícil ver como a primeira sintaxe é uma extensão natural da última, por sua vez proveniente do uso matemático.
ALGOL 58 , da mesma forma que FORTRAN, define ambas as 'funções' de linha única:
Uma declaração de função declara que uma determinada expressão é uma função de algumas de suas variáveis. Desse modo, a declaração fornece (para certas funções simples) a regra de cálculo para atribuir valores à função (cf. funções ) sempre que esta função aparecer em uma expressão.
Forma: Δ ~ I n (I, I, ~, I): = E em que I são identificadores e E é uma expressão que, entre seus constituintes, pode conter variáveis simples nomeadas por identificadores que aparecem entre parênteses.
e 'procedimentos', equivalente à definição atual de função (em linguagens de programação imperativas / procedurais, pelo menos). O valor de retorno é indicado da seguinte forma (p. 19):
Para cada procedimento de saída individual I (P i ) listado no título, um valor deve ser atribuído dentro do procedimento por uma declaração de atribuição “I: = E” onde I é o identificador que dá nome a esse procedimento.
Essas sintaxes foram posteriormente assumidas por alguns dialetos do BASIC (na forma de DEF FN
e mais tarde FUNCTION
) e do descendente do Pascal do ALGOL: nos compiladores Pascal da Borland, atribuir ao nome da função era a única sintaxe suportada antes da introdução da Result
variável no Delphi 1.0.
É provavelmente de Pascal que o comentador mencionado se lembrou; algumas universidades ainda ensinam programação nele, e geralmente mantêm a variedade padrão original, em vez de dialetos estendidos modernos como Object Pascal. (Isso não é realmente parte da questão, mas eu presumo que o mal-entendido do solicitante do StackOverflow veio disso também.)
TL; DR:
Eu diria que provavelmente é PASCAL, você se lembra, já que era bastante popular no início dos anos 80, usado em cursos universitários dos anos 80 até os 90 e ainda teve alguma bolsa depois, mais notavelmente Delphi.
Um pouco de história
A ideia básica é que o nome da função não está apenas reservado, portanto, não há necessidade de sugerir nada diferente e, usando-o, é uma declaração clara de que esse é o resultado. Também simplifica o projeto do compilador, pois um item de dados dedicado pode ser alocado dentro da convenção de chamada.
Existem essencialmente duas linhas de herança, FORTRAN e ALGOL.
Para ambos, alguns de seus descendentes mantiveram, como
- algumas variantes do BASIC de FORTRAN e
- Pascal e Modula do ALGOL.
Outros desistiram, como o acompanhamento do ALGOL
- BCPL, que introduziu a
return()
sintaxe,
o que é bastante comum hoje, visto que C o tirou do BCPL.
Idéias de linguagem são como genes pulando entre hospedeiros. Por exemplo, ADA, em muitos aspectos um neto ALGOL / PASCAL, também passou a usar um return
elemento.
Vovô FORTRAN tem, ao longo dos anos, variado a maneira como retorna os resultados das funções.
- Originalmente, o resultado de uma função foi atribuído ao identificador da função
- com FORTRAN 90 foi introduzida a definição explícita de um nome de retorno no cabeçalho da função.
Embora seja essencialmente apenas um açúcar sintático, ele apresenta uma mudança de estilo. O raciocínio aplicado foi que, com construções de recursão, como Foo = Foo(x-1)
ficaria estranho. Mas acho que isso depende da interpretação.
Curiosamente aqui também é que FORTRAN II de 1958 introduziu uma RETURN
instrução em seu esforço para adicionar programação procedural, mas seu uso era simplesmente para retornar a execução a um chamador, o valor de retorno teve que ser definido separadamente.
O Fortran usou essa sintaxe, desde a versão mais antiga que tinha funções até o Fortran 2008 e além.
No entanto, o Fortran 2008 tem uma opção (ainda mais confusa?) Onde você pode declarar um nome de variável diferente que é usado para retornar um valor de função! Por exemplo
function xyz(argument) result(answer)
...
answer = 42
...
end function xyz
em vez do estilo antigo
...
xyz = 42
...
Algol 60 para um.
Aqui estão as palavras relevantes do Relatório Revisado sobre o Algorithmic Language Algol 60 .
5.4.4. Valores de designadores de função.
Para que uma declaração de procedimento defina o valor de um designador de função, deve ocorrer, dentro do corpo da declaração de procedimento, uma ou mais instruções de atribuição explícitas com o identificador de procedimento em uma parte esquerda; pelo menos um deles deve ser executado, e o tipo associado ao identificador do procedimento deve ser declarado por meio da aparência de um declarador de tipo como o primeiro símbolo da declaração do procedimento. O último valor assim atribuído é usado para continuar a avaliação da expressão na qual o designador de função ocorre.
Qualquer ocorrência do identificador de procedimento dentro do corpo do procedimento, exceto na parte esquerda de uma instrução de atribuição, denota a ativação do procedimento.
A última frase é significativa - mostra que o nome do procedimento de tipo (função) não é tratado 'apenas como' uma variável dentro do corpo do procedimento (função); em vez disso, é apenas a atribuição que é especial.
No Algol 60, uma chamada para uma função que não leva argumentos não é seguida por parênteses vazios: portanto, em n := read
vez de n := read()
.
A última frase também é famosa por ser aquela que introduz procedimentos recursivos na linguagem. Mas isso não é pertinente a esta resposta.
BASIC é outra linguagem com funções em que alguns dialetos usavam atribuição ao nome da função para fornecer o valor de retorno. Os primeiros dialetos eram semelhantes às funções de linha única do Fortran:
DEF FND(x) = x*x
Mas os dialetos posteriores permitiram variantes mais complexas, semelhantes às funções multilinhas do Fortran :
DEF FNPeekWord& (A&)
FNPeekWord& = PEEK(A&) + 256& * PEEK(A& + 1)
END DEF
O MATLAB / Octave também faz isso.
É de 1984; então não tão velho quanto alguns dos outros.
Provavelmente estava imitando o Fortran, já que era originalmente concebido como uma ferramenta de alto nível. Além das bibliotecas Fortran como Linpack e Eispack.
Eu acredito que SNOBOL4 fez isso. http://berstis.com/greenbook.pdf
A seguir está um exemplo da definição e uso de uma função para calcular fatoriais 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) também retorna por atribuição à variável implícita. SystemVerilog adicionou a instrução "return", mas a atribuição clássica ainda está disponível.
Haskell (de 1990) também faz isso:
doubleMe x = x + x
define a função doubleMe
de um parâmetro x
e atribui o corpo da função x+x
a ele, consulte o ótimo Learn You A Haskell For Great Good
Pascal é um que eu pessoalmente usei para fazer isso. O Lisp comum meio que sorta-mas-não-realmente faz isso, pois os valores de retorno são quase sempre implícitos (ou seja, cada instrução tem um valor, e o último valor em um bloco é o valor de retorno do bloco), então você raramente vê uma instrução de retorno explícito, mas quando você precisa de retornar um valor e não pode usar o modo implícito, a maneira de fazer isso é usando o RETURN-FROM
[*] declaração, assim: (return-from function-name value)
.
[*] Também existe uma RETURN
instrução, mas é uma abreviação de (return-from nil value)
e não terá o efeito de criar VALUE
o valor da função na qual foi executada. É uma grande armadilha para iniciantes vindos de C e seus descendentes.