In quale lingua è impostato il valore di ritorno assegnando al nome della funzione?
In questa domanda di Stack Overflow il codice originale ha commesso l'errore di utilizzare il nome della funzione come variabile e le ha assegnato il valore di ritorno. Un commentatore ha detto di aver usato una volta un linguaggio in cui questo era il modo in cui restituivi il valore dalle funzioni. Il commento dice "So che una volta ho usato una lingua in cui il valore di ritorno di una funzione doveva essere assegnato al nome della funzione. È così antico e obsoleto che non riesco nemmeno a ricordare quale lingua fosse".
Anche questo suona familiare a me, ma non ricordo nemmeno che lingua fosse.
Qualcuno ha una memoria migliore di noi e può dirci di che lingua è?
Risposte
Pascal fa questo, non ne conosco altri. Non so se la pratica va avanti con altre lingue Wirth.
Le lingue della famiglia Visual Basic fanno esattamente questo. Ciò include VBScript, VBA, Visual Basic e versioni precedenti. Credo che questi ereditino la "caratteristica" di QBASIC. Per esempio
Public Function AddTwo(something as Integer)
AddTwo = something + 2
End Function
Fortran, di sicuro:
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
(dalla Guida per programmatori professionisti di Clive G. Page a Fortran77 ).
È anche definito in questo modo nello standard Fortran ANSI X 3.9 1966 Fortran 66 .
Le prime lingue di questo tipo che riesco a trovare sono FORTRAN II e ALGOL 58, entrambi pubblicati nello stesso anno 1958; sebbene l'originale FORTRAN (1956) possa senza dubbio essere incluso.
Per FORTRAN, la prima pagina del capitolo del manuale che copre le funzioni contiene questo esempio (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 include anche un'altra sintassi di funzione (p. 10), la definizione di funzione a riga singola, ereditata dal suo predecessore:
FIRSTF(X) = A*X + B
Non è difficile vedere come la prima sintassi sia una naturale estensione della seconda, a sua volta derivante dall'uso matematico.
ALGOL 58 , analogamente a FORTRAN, definisce entrambe le 'funzioni' a riga singola:
Una dichiarazione di funzione dichiara che una data espressione è una funzione di alcune delle sue variabili. In tal modo, la dichiarazione fornisce (per alcune funzioni semplici) la regola di calcolo per assegnare valori alla funzione (cfr. Funzioni ) ogni volta che questa funzione appare in un'espressione.
Forma: Δ ~ I n (I, I, ~, I): = E dove gli io sono identificatori ed E è un'espressione che, tra i suoi costituenti, può contenere semplici variabili nominate da identificatori che compaiono tra parentesi.
e "procedure", equivalenti a una definizione di funzione odierna (almeno nei linguaggi di programmazione imperativi / procedurali). Il valore restituito è indicato come segue (p. 19):
Per ogni singola procedura di output I (P i ) elencata nell'intestazione, deve essere assegnato un valore all'interno della procedura mediante un'istruzione di assegnazione “I: = E” dove I è l'identificativo che denomina tale procedura.
Queste sintassi furono successivamente riprese da alcuni dialetti del BASIC (sotto forma di DEF FN
e successivi FUNCTION
) e del discendente Pascal di ALGOL: nei compilatori Pascal di Borland, l'assegnazione al nome della funzione era l'unica sintassi supportata prima dell'introduzione della Result
variabile in Delphi 1.0.
È probabilmente Pascal quello che il commentatore menzionato ha ricordato; alcune università insegnano ancora la programmazione al suo interno e di solito si attengono alla varietà standard originale, invece dei dialetti estesi moderni come Object Pascal. (Questo non fa davvero parte della domanda, ma presumo che l'incomprensione del richiedente StackOverflow derivi anche da questo.)
TL; DR:
Direi, molto probabilmente è PASCAL che ricordi, dato che era piuttosto popolare nei primi anni '80, usato nei corsi universitari dagli anni '80 fino agli anni '90 e aveva ancora qualche amicizia lì dopo, in particolare Delphi.
Un po 'di storia
L'idea di base è che il nome della funzione non solo è già riservato, quindi non è necessario inventare qualcosa di diverso, e usarlo è una chiara affermazione che questo è il risultato. Inoltre semplifica la progettazione del compilatore, poiché un elemento di dati dedicato può essere allocato all'interno della convenzione di chiamata.
Esistono essenzialmente due linee di eredità, FORTRAN e ALGOL.
Per entrambi alcuni dei loro discendenti lo tenevano, tipo
- alcune varianti BASIC da FORTRAN e
- Pascal e Modula di ALGOL.
Altri lo hanno lasciato cadere, come il seguito di ALGOL
- BCPL, che ha introdotto la
return()
sintassi,
che è abbastanza comune oggi poiché C lo ha preso da BCPL.
Le idee linguistiche sono come i geni che saltano tra gli ospiti. Ad esempio ADA, per molti versi un nipote di ALGOL / PASCAL, si è rivolto anche lui all'utilizzo di un return
elemento.
Granddaddy FORTRAN, nel corso degli anni, ha modificato il modo in cui restituisce i risultati delle funzioni.
- Originariamente il risultato di una funzione era assegnato all'identificatore della funzione
- con FORTRAN 90 è stata introdotta la definizione esplicita di un nome di ritorno nell'intestazione della funzione.
Sebbene questo sia essenzialmente solo zucchero sintattico, presenta un cambiamento di stile. Il ragionamento applicato era che con costruzioni di ricorsione il simile Foo = Foo(x-1)
sarebbe apparso strano. Ma immagino che dipenda dall'interpretazione.
È interessante notare che anche qui FORTRAN II del 1958 ha introdotto RETURN
un'istruzione nel suo tentativo di aggiungere la programmazione procedurale, ma il suo utilizzo era semplicemente quello di restituire l'esecuzione a un chiamante, il valore restituito doveva essere impostato separatamente.
Fortran ha utilizzato questa sintassi, dalla prima versione che aveva tutte le funzioni fino a Fortran 2008 e oltre.
Tuttavia Fortran 2008 ha un'opzione (ancora più confusa?) In cui è possibile dichiarare un nome di variabile diverso che viene utilizzato per restituire un valore di funzione! Per esempio
function xyz(argument) result(answer)
...
answer = 42
...
end function xyz
invece del vecchio stile
...
xyz = 42
...
Algol 60 per uno.
Ecco le parole rilevanti dal Rapporto Rivisto sul Linguaggio Algoritmico Algol 60 .
5.4.4. Valori dei designatori di funzione.
Affinché una dichiarazione di procedura definisca il valore di un designatore di funzione, devono essere presenti, all'interno del corpo della dichiarazione di procedura, una o più istruzioni di assegnazione esplicita con l'identificatore di procedura nella parte sinistra; almeno uno di questi deve essere eseguito e il tipo associato all'identificatore di procedura deve essere dichiarato attraverso la comparsa di un dichiaratore di tipo come primo simbolo della dichiarazione di procedura. L'ultimo valore così assegnato viene utilizzato per continuare la valutazione dell'espressione in cui ricorre il designatore di funzione.
Qualsiasi occorrenza dell'identificativo della procedura all'interno del corpo della procedura diversa dalla parte sinistra di un'istruzione di assegnazione denota l'attivazione della procedura.
L'ultima frase è significativa: mostra che il nome del tipo procedura (funzione) non è trattato "proprio come" una variabile all'interno del corpo della procedura (funzione); piuttosto, è solo un incarico che è un caso speciale.
In Algol 60, una chiamata a una funzione che non accetta argomenti non è seguita da parentesi vuote: quindi n := read
piuttosto che n := read()
.
L'ultima frase è anche famosa come la frase che ha ottenuto procedure ricorsive nella lingua. Ma questo non è pertinente a questa risposta.
BASIC è un altro linguaggio con funzioni in cui alcuni dialetti usavano l'assegnazione al nome della funzione per fornire il valore di ritorno. I primi dialetti erano simili alle funzioni a riga singola di Fortran:
DEF FND(x) = x*x
Ma i dialetti successivi consentirono varianti più complesse, simili alle funzioni multilinea di Fortran :
DEF FNPeekWord& (A&)
FNPeekWord& = PEEK(A&) + 256& * PEEK(A& + 1)
END DEF
Anche MATLAB / Octave fa questo.
È del 1984; quindi non vecchio come alcuni degli altri.
Probabilmente stava imitando Fortran, poiché era originariamente concepito come uno strumento di alto livello. Oltre alle librerie Fortran come Linpack ed Eispack.
Credo che SNOBOL4 abbia fatto questo. http://berstis.com/greenbook.pdf
Quello che segue è un esempio della definizione e dell'uso di una funzione per calcolare fattoriali di numeri:
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) restituisce anche per assegnazione alla variabile implicita. SystemVerilog ha aggiunto l'istruzione "return" ma l'assegnazione classica è ancora disponibile.
Anche Haskell (dal 1990) fa questo:
doubleMe x = x + x
definisce una funzione doubleMe
di un parametro x
e gli assegna il corpo della funzione x+x
, vedere il grande Learn You A Haskell For Great Good
Pascal è uno che ho usato personalmente per farlo. Common Lisp un po '-sorta-ma-non-lo fa davvero, in quanto i valori di ritorno sono quasi sempre impliciti (cioè ogni istruzione ha un valore e l'ultimo valore in un blocco è il valore di ritorno del blocco), quindi molto raramente vedi una dichiarazione di ritorno esplicito, ma quando è necessario restituire un valore e non è possibile utilizzare il modo implicito, il modo per farlo è quello di utilizzare il RETURN-FROM
[*] dichiarazione, in questo modo: (return-from function-name value)
.
[*] C'è anche RETURN
un'istruzione, ma è un'abbreviazione per (return-from nil value)
e non avrà l'effetto di rendere VALUE
il valore della funzione in cui è stata eseguita. È una grande trappola per i neofiti provenienti da C e dai suoi discendenti.