Für heutige Sprachen ist es nur syntaktischer Zucker; In einer völlig sprachunabhängigen Art und Weise ist es mehr als das.
Früher hat diese Antwort einfach gesagt, dass es mehr als syntaktischer Zucker ist, aber wenn Sie in den Kommentaren sehen, hat Falco den Punkt angesprochen, dass es ein Puzzlestück gibt, das allen modernen Sprachen fehlt. Sie kombinieren Methodenüberladung nicht mit der dynamischen Bestimmung, welche Funktion im selben Schritt aufgerufen werden soll. Dies wird später noch geklärt.
Hier ist , warum es sollte mehr sein.
Stellen Sie sich eine Sprache vor, die sowohl Methodenüberladung als auch untypisierte Variablen unterstützt. Sie könnten die folgenden Methodenprototypen haben:
bool someFunction(int arg);
bool someFunction(string arg);
In einigen Sprachen sind Sie wahrscheinlich damit abgefunden, beim Kompilieren zu wissen, welche davon von einer bestimmten Codezeile aufgerufen wird. In einigen Sprachen werden jedoch nicht alle Variablen eingegeben (oder sie werden alle implizit als Object
oder wie auch immer eingegeben ). Stellen Sie sich daher vor, Sie erstellen ein Wörterbuch, dessen Schlüssel Werten verschiedener Typen zugeordnet sind:
dict roomNumber; // some hotels use numbers, some use letters, and some use
// alphanumerical strings. In some languages, built-in dictionary
// types automatically use untyped values for their keys to map to,
// so it makes more sense then to allow for both ints and strings in
// your code.
Was wäre, wenn Sie sich für someFunction
eine dieser Zimmernummern bewerben wollten ? Sie nennen das:
someFunction(roomNumber[someSortOfKey]);
Heißt someFunction(int)
oder someFunction(string)
heißt? Hier sehen Sie ein Beispiel, bei dem es sich nicht um vollständig orthogonale Methoden handelt, insbesondere in höheren Sprachen. Die Sprache muss - während der Laufzeit - herausfinden, welche davon aufgerufen werden sollen, und muss diese daher immer noch als mindestens einigermaßen dieselbe Methode betrachten.
Warum nicht einfach Vorlagen verwenden? Warum nicht einfach ein untypisiertes Argument verwenden?
Flexibilität und feinkörnigere Kontrolle. Manchmal ist die Verwendung von Vorlagen / untypisierten Argumenten besser, manchmal jedoch nicht.
Sie müssen sich Fälle überlegen, in denen Sie beispielsweise zwei Methodensignaturen haben, die jeweils ein int
und ein string
als Argument verwenden, bei denen die Reihenfolge in jeder Signatur jedoch unterschiedlich ist. Möglicherweise haben Sie einen guten Grund, dies zu tun, da die Implementierung jeder Signatur im Großen und Ganzen dasselbe tut, jedoch mit einer geringfügig anderen Wendung. Die Protokollierung kann beispielsweise unterschiedlich sein. Selbst wenn sie genau dasselbe tun, können Sie möglicherweise bestimmte Informationen automatisch aus der Reihenfolge abrufen, in der die Argumente angegeben wurden. Technisch könnte man einfach Pseudo-Switch-Anweisungen verwenden, um den Typ jedes der übergebenen Argumente zu bestimmen, aber das wird chaotisch.
Ist das nächste Beispiel also eine schlechte Programmierpraxis?
bool stringIsTrue(int arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
bool stringIsTrue(Object arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
bool stringIsTrue(string arg)
{
if (arg == "0")
{
return false;
}
else
{
return true;
}
}
Ja, im Großen und Ganzen. In diesem speziellen Beispiel könnte es jemanden davon abhalten, dies auf bestimmte primitive Typen anzuwenden und unerwartetes Verhalten zurückzugewinnen (was eine gute Sache sein könnte); aber nehmen wir einfach an, dass ich den obigen Code abgekürzt habe und dass Sie tatsächlich Überladungen für alle primitiven Typen sowie für Object
s haben. Dann ist dieses nächste Stück Code wirklich angemessener:
bool stringIsTrue(untyped arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
Aber was ist, wenn Sie dies nur für int
s und string
s benötigen und wenn Sie möchten, dass es unter einfacheren oder komplizierteren Bedingungen als wahr zurückgegeben wird? Dann haben Sie einen guten Grund, Überladung zu verwenden:
bool appearsToBeFirstFloor(int arg)
{
if (arg.digitAt(0) == 1)
{
return true;
}
else
{
return false;
}
}
bool appearsToBeFirstFloor(string arg)
{
string firstCharacter = arg.characterAt(0);
if (firstCharacter.isDigit())
{
return appearsToBeFirstFloor(int(firstCharacter));
}
else if (firstCharacter.toUpper() == "A")
{
return true;
}
else
{
return false;
}
}
Aber warum geben Sie diesen Funktionen nicht einfach zwei unterschiedliche Namen? Sie haben immer noch die gleiche Kontrolle, nicht wahr?
Wie bereits erwähnt, verwenden einige Hotels Zahlen, einige Buchstaben und einige eine Mischung aus Zahlen und Buchstaben:
appearsToBeFirstFloor(roomNumber[someSortOfKey]);
// will treat ints and strings differently, without you having to write extra code
// every single spot where the function is being called
Dies ist immer noch nicht genau derselbe genaue Code, den ich im wirklichen Leben verwenden würde, aber er sollte den Punkt veranschaulichen, den ich gerade gut mache.
Aber ... Deshalb ist es in modernen Sprachen nicht mehr als syntaktischer Zucker.
Falco wies in den Kommentaren darauf hin, dass derzeitige Sprachen Methodenüberladung und dynamische Funktionsauswahl grundsätzlich nicht im selben Schritt mischen. Früher verstand ich bestimmte Sprachen so, dass Sie sie appearsToBeFirstFloor
im obigen Beispiel überladen konnten. Die Sprache bestimmte dann zur Laufzeit, welche Version der Funktion aufgerufen werden soll, abhängig vom Laufzeitwert der untypisierten Variablen. Diese Verwirrung ergab sich teilweise aus der Arbeit mit ECMA-Sprachen wie ActionScript 3.0, in denen Sie leicht nach dem Zufallsprinzip bestimmen können, welche Funktion zur Laufzeit in einer bestimmten Codezeile aufgerufen wird.
Wie Sie vielleicht wissen, unterstützt ActionScript 3 das Überladen von Methoden nicht. Wie bei VB.NET können Sie Variablen deklarieren und festlegen, ohne explizit einen Typ zuzuweisen. Wenn Sie jedoch versuchen, diese Variablen als Argumente an überladene Methoden zu übergeben, möchten Sie den Laufzeitwert nicht lesen, um zu bestimmen, welche Methode aufgerufen werden soll. es möchte stattdessen eine Methode mit Argumenten vom Typ Object
oder ohne Typ oder so etwas finden. Das obige int
vs. string
Beispiel würde also auch in dieser Sprache nicht funktionieren. C ++ hat ähnliche Probleme, wie wenn Sie so etwas wie einen Void-Zeiger oder einen anderen Mechanismus wie diesen verwenden, müssen Sie den Typ beim Kompilieren immer noch manuell disambiguieren.
Also wie der erste Header sagt ...
Für heutige Sprachen ist es nur syntaktischer Zucker; In einer völlig sprachunabhängigen Art und Weise ist es mehr als das. Das Überladen von Methoden nützlicher und relevanter zu machen, wie im obigen Beispiel, kann tatsächlich eine gute Funktion sein, um eine vorhandene Sprache zu ergänzen (wie dies für AS3 allgemein implizit gefordert wurde), oder es könnte auch als eine von vielen verschiedenen Grundpfeilern für dienen die Schaffung einer neuen prozeduralen / objektorientierten Sprache.