In welchen Sprachen wird der Rückgabewert durch Zuweisen zum Funktionsnamen festgelegt?
In dieser Frage zum Stapelüberlauf hat der ursprüngliche Code den Fehler gemacht, den Funktionsnamen als Variable zu verwenden, und ihm den Rückgabewert zugewiesen. Ein Kommentator erwähnte, dass er einmal eine Sprache verwendet habe, in der Sie auf diese Weise den Wert von Funktionen zurückgegeben haben. Der Kommentar lautet: "Ich weiß, dass ich einmal eine Sprache verwendet habe, in der der Rückgabewert einer Funktion dem Namen der Funktion zugewiesen werden musste. Sie ist so alt und veraltet, dass ich mich nicht einmal daran erinnern kann, welche Sprache sie war."
Das kommt mir auch bekannt vor, aber ich kann mich auch nicht erinnern, welche Sprache es war.
Hat jemand ein besseres Gedächtnis als wir und kann uns sagen, um welche Sprache es sich handelt?
Antworten
Pascal macht das, ich kenne keine anderen. Ich weiß nicht, ob die Praxis mit anderen Wirth-Sprachen voranschreitet.
Die Sprachen in der Visual Basic-Familie tun genau dies. Dies umfasst VBScript, VBA, Visual Basic und frühere Versionen. Ich glaube, diese erben das "Feature" von QBASIC. Beispielsweise
Public Function AddTwo(something as Integer)
AddTwo = something + 2
End Function
Fortran sicher:
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
(aus dem Professional Programmer's Guide von Clive G. Page zu Fortran77 ).
Dies ist auch im Fortran ANSI X 3.9 1966 Fortran 66- Standard definiert.
Die frühesten Sprachen, die ich finden kann, sind FORTRAN II und ALGOL 58, beide im selben Jahr 1958 veröffentlicht; obwohl das Original FORTRAN (1956) wohl auch enthalten sein kann.
Für FORTRAN enthält die erste Seite des Handbuchkapitels mit Funktionen dieses Beispiel (S. 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 enthält auch eine andere Funktionssyntax (S. 10), die einzeilige Funktionsdefinition, die von seinem Vorgänger geerbt wurde:
FIRSTF(X) = A*X + B
Es ist nicht schwer zu erkennen, dass die erstere Syntax eine natürliche Erweiterung der letzteren ist, die wiederum aus der mathematischen Verwendung stammt.
ALGOL 58 definiert ähnlich wie FORTRAN beide einzeiligen 'Funktionen':
Eine Funktionsdeklaration deklariert einen bestimmten Ausdruck als Funktion bestimmter seiner Variablen. Dabei gibt die Deklaration (für bestimmte einfache Funktionen) die Rechenregel zum Zuweisen von Werten zur Funktion (vgl. Funktionen ) an, wenn diese Funktion in einem Ausdruck vorkommt.
Form: Δ ~ I n (I, I, ~, I): = E wobei das I Bezeichner sind und E ein Ausdruck ist, der unter seinen Bestandteilen einfache Variablen enthalten kann, die durch in den Klammern stehende Bezeichner benannt sind.
und "Prozeduren", die einer heutigen Funktionsdefinition entsprechen (zumindest in imperativen / prozeduralen Programmiersprachen). Der Rückgabewert wird wie folgt angegeben (S. 19):
Für jede einzelne Ausgabeprozedur I (P i ), die in der Überschrift aufgeführt ist, muss innerhalb der Prozedur ein Wert durch eine Zuweisungsanweisung "I: = E" zugewiesen werden, wobei I die Kennung ist, die diese Prozedur benennt.
Diese Syntaxen wurden später von einigen Dialekten von BASIC (in Form von DEF FN
und später FUNCTION
) und ALGOLs Nachkommen Pascal aufgegriffen : In Borlands Pascal-Compilern war die Zuweisung des Funktionsnamens die einzige unterstützte Syntax vor der Einführung der Result
Variablen in Delphi 1.0.
Es ist wahrscheinlich Pascal, an den sich der erwähnte Kommentator erinnerte; Einige Universitäten unterrichten immer noch Programmieren darin und halten sich normalerweise an die ursprüngliche Standardvariante anstatt an moderne erweiterte Dialekte wie Object Pascal. (Dies ist nicht wirklich Teil der Frage, aber ich würde annehmen, dass das Missverständnis des StackOverflow-Fragestellers auch darauf zurückzuführen ist.)
TL; DR:
Ich würde sagen, höchstwahrscheinlich ist es PASCAL, wie Sie sich erinnern, da es in den frühen 80ern ziemlich beliebt war, in Universitätskursen bis in die 80er Jahre bis in die 90er Jahre verwendet wurde und danach immer noch ein Stipendium hatte, insbesondere Delphi.
Einige Geschichten
Die Grundidee ist, dass der Funktionsname nicht nur bereits reserviert ist, sondern dass Sie sich nichts anderes einfallen lassen müssen. Die Verwendung dieses Namens ist eine klare Aussage, dass dies das Ergebnis ist. Es vereinfacht auch das Compiler-Design, da ein dediziertes Datenelement innerhalb der aufrufenden Konvention zugewiesen werden kann.
Es gibt im Wesentlichen zwei Linien des Erbes, FORTRAN und ALGOL.
Für beide behielten einige ihrer Nachkommen es, wie
- einige BASIC-Varianten von FORTRAN und
- Pascal und Modula von ALGOL.
Andere ließen es fallen, wie das ALGOL-Follow-up
- BCPL, das die
return()
Syntax einführte ,
Das ist heute ziemlich üblich, da C es von BCPL übernommen hat.
Sprachideen sind wie Gene, die zwischen Wirten springen. Zum Beispiel hat sich ADA, in vielerlei Hinsicht ein ALGOL / PASCAL-Enkelkind, auch der Verwendung eines return
Elements zugewandt .
Großvater FORTRAN hat im Laufe der Jahre die Art und Weise, wie Funktionsergebnisse zurückgegeben werden, variiert.
- Ursprünglich wurde das Ergebnis einer Funktion dem Bezeichner der Funktion zugewiesen
- Mit FORTRAN 90 wurde die explizite Definition eines Rückgabennamens im Funktionskopf eingeführt.
Während dies im Wesentlichen nur syntaktischer Zucker ist, ändert sich der Stil. Die Argumentation war, dass mit Rekursionskonstruktionen wie Foo = Foo(x-1)
seltsam aussehen würde. Aber ich denke, das liegt an der Interpretation.
Interessanterweise hat FORTRAN II von 1958 auch eine RETURN
Erklärung in sein Bestreben aufgenommen, prozedurale Programmierung hinzuzufügen, aber es wurde lediglich verwendet, um die Ausführung an einen Aufrufer zurückzugeben. Der Rückgabewert musste separat festgelegt werden.
Fortran hat diese Syntax verwendet, von der frühesten Version, die überhaupt Funktionen hatte, bis Fortran 2008 und darüber hinaus.
Fortran 2008 hat jedoch eine (noch verwirrendere?) Option, mit der Sie einen anderen Variablennamen deklarieren können, der zur Rückgabe eines Funktionswerts verwendet wird! Beispielsweise
function xyz(argument) result(answer)
...
answer = 42
...
end function xyz
anstelle des alten Stils
...
xyz = 42
...
Algol 60 für einen.
Hier sind die relevanten Wörter aus dem überarbeiteten Bericht über die algorithmische Sprache Algol 60 .
5.4.4. Werte von Funktionsbezeichnern.
Damit eine Prozedurdeklaration den Wert eines Funktionsbezeichners definiert, müssen innerhalb des Prozedurdeklarationskörpers eine oder mehrere explizite Zuweisungsanweisungen mit der Prozedurkennung in einem linken Teil auftreten. Mindestens eine davon muss ausgeführt werden, und der mit der Prozedurkennung verknüpfte Typ muss durch das Erscheinen eines Typdeklarators als erstes Symbol der Prozedurdeklaration deklariert werden. Der zuletzt zugewiesene Wert wird verwendet, um die Auswertung des Ausdrucks fortzusetzen, in dem der Funktionsbezeichner vorkommt.
Jedes Auftreten der Prozedurkennung innerhalb des Hauptteils der Prozedur, außer in einem linken Teil in einer Zuweisungsanweisung, bedeutet die Aktivierung der Prozedur.
Der letzte Satz ist von Bedeutung - er zeigt, dass der Name des Typs Prozedur (Funktion) nicht wie eine Variable innerhalb des Prozedurkörpers (Funktionskörpers) behandelt wird. Vielmehr ist es nur eine Aufgabe, die speziell behandelt wird.
In Algol 60 folgen auf einen Aufruf einer Funktion, die keine Argumente akzeptiert, keine leeren Klammern: also n := read
nicht n := read()
.
Der letzte Satz ist auch als der Satz bekannt , der rekursive Prozeduren in die Sprache gebracht hat. Aber das ist für diese Antwort nicht relevant.
BASIC ist eine andere Sprache mit Funktionen, bei denen einige Dialekte die Zuordnung zum Funktionsnamen verwendeten, um den Rückgabewert bereitzustellen. Die frühesten Dialekte ähnelten den einzeiligen Funktionen von Fortran:
DEF FND(x) = x*x
Spätere Dialekte erlaubten jedoch komplexere Varianten, ähnlich den mehrzeiligen Funktionen von Fortran :
DEF FNPeekWord& (A&)
FNPeekWord& = PEEK(A&) + 256& * PEEK(A& + 1)
END DEF
MATLAB / Octave macht das auch.
Es ist von 1984; also nicht so alt wie einige der anderen.
Es ahmte wahrscheinlich Fortran nach, da es ursprünglich als hochrangiges Werkzeug gedacht war. Zusätzlich zu den Fortran-Bibliotheken wie Linpack und Eispack.
Ich glaube, dass SNOBOL4 dies getan hat. http://berstis.com/greenbook.pdf
Das Folgende ist ein Beispiel für die Definition und Verwendung einer Funktion zum Berechnen von Fakultäten von Zahlen:
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) kehrt ebenfalls durch Zuordnung zur impliziten Variablen zurück. SystemVerilog hat die Anweisung "return" hinzugefügt, die klassische Zuweisung ist jedoch weiterhin verfügbar.
Haskell (ab 1990) macht das auch:
doubleMe x = x + x
definiert eine Funktion doubleMe
eines Parameters x
und weist ihm den Funktionskörper x+x
zu, siehe das große Learn You A Haskell For Great Good
Pascal ist einer, den ich persönlich benutzt habe, um das zu tun. Common Lisp tut es irgendwie, aber nicht wirklich, da Rückgabewerte fast immer implizit sind (dh jede Anweisung hat einen Wert und der letzte Wert in einem Block ist der Rückgabewert des Blocks), so dass Sie sehr selten sehen Eine explizite return-Anweisung. Wenn Sie jedoch einen Wert zurückgeben müssen und die implizite Methode nicht verwenden können, verwenden Sie dazu die Anweisung RETURN-FROM
[*] wie folgt : (return-from function-name value)
.
[*] Es gibt auch eine RETURN
Anweisung, aber sie ist eine Abkürzung für (return-from nil value)
und hat keine Auswirkung auf VALUE
den Wert der Funktion, in der sie ausgeführt wurde. Es ist eine große Gefahr für Neulinge aus C und seinen Nachkommen.