Ich entwickle eine statisch und stark typisierte, kompilierte Sprache und überlege mir, ob ich Funktionsüberladung als Sprachfeature einbeziehen soll. Mir wurde klar, dass ich ein bisschen voreingenommen bin, hauptsächlich aus dem C[++|#]
Hintergrund.
Was sind die überzeugendsten Argumente für und gegen das Einbeziehen einer Funktionsüberladung in eine Sprache?
EDIT: Gibt es niemanden, der eine gegenteilige Meinung hat?
Bertrand Meyer (Schöpfer von Eiffel 1985/86) nennt eine Methode, die dies überlastet: (Quelle)
Ein Vanity-Mechanismus, der nichts zur semantischen Kraft einer OO-Sprache beiträgt, aber die Lesbarkeit beeinträchtigt und die Arbeit aller erschwert
Nun, das sind einige pauschale Verallgemeinerungen, aber er ist ein kluger Kerl, und ich denke, es ist sicher zu sagen, dass er sie unterstützen könnte, wenn er muss. Fast hätte er Brad Abrams (einen der CLSv1-Entwickler) davon überzeugt, dass .NET das Überladen von Methoden nicht unterstützen sollte. (Quelle) Das ist mächtiges Zeug. Kann irgendjemand etwas Licht in seine Gedanken bringen und ob sein Standpunkt nach 25 Jahren noch gerechtfertigt ist?
quelle
Ich empfehle, zumindest die Typenklassen in Haskell zu kennen. Typklassen wurden als disziplinierter Ansatz für das Überladen von Operatoren entwickelt, haben jedoch andere Verwendungszwecke gefunden und Haskell in gewissem Maße zu dem gemacht, was es ist.
Beispiel für eine Ad-hoc-Überladung (nicht ganz gültiges Haskell):
Und hier ist das gleiche Beispiel für das Überladen mit Typklassen:
Ein Nachteil davon ist , dass Sie mit funky Namen für alle Ihre typeclasses zu kommen haben (wie in Haskell, haben Sie die eher abstrakt
Monad
,Functor
,Applicative
sowie die einfachere und besser erkennbarEq
,Num
undOrd
).Ein Vorteil ist, dass Sie, sobald Sie mit einer Typenklasse vertraut sind, wissen, wie Sie einen Typ in dieser Klasse verwenden. Außerdem ist es einfach, Funktionen vor Typen zu schützen, die die erforderlichen Klassen nicht implementieren, wie in:
Bearbeiten: Wenn Sie in Haskell einen
==
Operator benötigen, der zwei verschiedene Typen akzeptiert, können Sie eine Typklasse mit mehreren Parametern verwenden:Natürlich ist dies wahrscheinlich eine schlechte Idee, da Sie damit explizit Äpfel und Orangen vergleichen können. Sie sollten dies jedoch in Betracht ziehen
+
, da das Hinzufügen von aWord8
zuInt
a in manchen Kontexten sinnvoll ist.quelle
(==) :: Int -> Float -> Bool
irgendwo zu definieren ? (Unabhängig davon, ob es eine gute Idee ist, natürlich)class Eq a ...
wäre das also eine Übersetzung in eine Pseudo-C-Familie.interface Eq<A> {bool operator==(A x, A y);}
Anstatt Vorlagencode zum Vergleichen beliebiger Objekte zu verwenden, verwenden Sie diese „Schnittstelle“. Ist das richtig?==
, sich in einem anderen Namensraum zu befinden, aber es erlaubt nicht, ihn zu überschreiben. Beachten Sie, dassPrelude
standardmäßig ein einzelner Namespace ( ) enthalten ist. Sie können das Laden jedoch verhindern, indem Sie Erweiterungen verwenden oder ihn explizit importieren (esimport Prelude ()
wird nichts aus dem aktuellen Namespace importiertPrelude
undimport qualified Prelude as P
keine Symbole in den aktuellen Namespace eingefügt).Erlaube das Überladen von Funktionen, du kannst das Folgende nicht mit optionalen Parametern machen (oder wenn du kannst, nicht gut).
triviales Beispiel setzt keine Methode voraus
base.ToString()
quelle
Ich habe immer Standardparameter der Funktionsüberladung vorgezogen. Überladene Funktionen rufen im Allgemeinen nur eine "Standard" -Version mit Standardparametern auf. Warum schreiben?
Wann könnte ich tun:
Trotzdem stelle ich fest, dass manchmal überladene Funktionen andere Dinge tun, als nur eine andere Variante mit Standardparametern aufzurufen. Aber in einem solchen Fall ist es keine schlechte Idee (in der Tat ist es wahrscheinlich eine gute Idee), einfach eine zu geben anderer Name.
(Außerdem funktionieren Schlüsselwortargumente im Python-Stil sehr gut mit Standardparametern.)
quelle
Array Slice(int start, int length) {...}
überladenArray Slice(int start) {return this.Slice(start, this.Count - start);}
? Das kann nicht mit Standardparametern codiert werden. Denkst du, sie sollten unterschiedliche Namen bekommen? Wenn ja, wie würden Sie sie nennen?indexOf(char ch)
+indexOf(Date dt)
auf einer Liste. Ich mag auch Standardwerte, aber sie sind nicht mit statischer Eingabe austauschbar.Sie haben gerade Java beschrieben. Oder C #.
Warum erfindest du das Rad neu?
Vergewissern Sie sich, dass der Rückgabetyp Teil der Methodensignatur ist, undbereinigen Sie den Code wirklich, wenn Sie nichts sagen müssen.quelle
EnumX.Flag1 | Flag2 | Flag3
. Ich werde dies jedoch nicht implementieren. Wenn ich es täte und der Rückgabetyp nicht verwendet würde, würde ich nach einem Rückgabetyp von suchenvoid
.Grrr .. nicht genug Privileg, um noch zu kommentieren ..
@Mason Wheeler: Achte dann auf Ada, die bei Rückgabetyp überlastet. Auch meine Sprache Felix macht das in einigen Kontexten, insbesondere wenn eine Funktion eine andere Funktion zurückgibt und ein Aufruf wie folgt erfolgt:
Der Typ b kann für die Überlastungsauflösung verwendet werden. Unter bestimmten Umständen auch C ++ - Überladungen beim Rückgabetyp:
Tatsächlich gibt es Algorithmen zum Überladen des Rückgabetyps mithilfe von Typinferenz. Es ist eigentlich gar nicht so schwer mit einer Maschine umzugehen, das Problem ist, dass Menschen es schwer finden. (Ich denke, der Umriss ist im Drachenbuch angegeben, der Algorithmus wird Wippalgorithmus genannt, wenn ich mich richtig erinnere.)
quelle
Anwendungsfall gegen das Implementieren von Funktionsüberladung: 25 gleichnamige Methoden, die die gleichen Aktionen ausführen, jedoch mit völlig unterschiedlichen Argumenten in einer Vielzahl von Mustern.
Anwendungsfall gegen die Nichtimplementierung von Funktionsüberladungen: 5 Methoden mit ähnlichen Namen und sehr ähnlichen Typengruppen im exakt gleichen Muster.
Letztendlich freue ich mich nicht darauf, die Dokumente für eine API zu lesen, die in beiden Fällen erstellt wurde.
Aber in einem Fall geht es darum, was Benutzer tun könnten. Im anderen Fall müssen die Benutzer dies aufgrund einer Spracheinschränkung tun. IMO, es ist besser, zumindest die Möglichkeit zu berücksichtigen, dass Programmautoren klug genug sind, um vernünftig zu überladen, ohne Mehrdeutigkeiten zu erzeugen. Wenn Sie ihre Hände schlagen und die Option wegnehmen, garantieren Sie im Grunde genommen, dass Unklarheiten auftreten werden. Ich vertraue eher darauf, dass der Benutzer das Richtige tut, als davon auszugehen, dass er immer das Falsche tut. Nach meiner Erfahrung führt Protektionismus zu einem noch schlimmeren Verhalten der Sprachgemeinschaft.
quelle
Ich habe mich dafür entschieden, in meiner Sprache Felix gewöhnliche Überladungs- und Mehrfachtypklassen anzubieten.
Ich halte (offenes) Überladen für wesentlich, besonders in einer Sprache, die viele numerische Typen hat (Felix hat alle numerischen Typen von C). Im Gegensatz zu C ++, das das Überladen missbraucht, indem Vorlagen davon abhängig gemacht werden, ist der Felix-Polymorphismus jedoch parametrisch: Sie müssen Vorlagen in C ++ überladen, da Vorlagen in C ++ schlecht gestaltet sind.
Typenklassen werden auch in Felix angeboten. Ignorieren Sie diejenigen, die C ++ kennen, aber Haskell nicht befassen, die es als überladen bezeichnen. Es ist nicht wie eine Überladung aus der Ferne, sondern wie eine Template-Spezialisierung: Sie deklarieren ein Template, das Sie nicht implementieren, und stellen dann Implementierungen für bestimmte Fälle zur Verfügung, wenn Sie sie benötigen. Die Typisierung ist parametrisch polymorph, die Implementierung erfolgt durch Ad-hoc-Instanziierung, soll jedoch nicht uneingeschränkt sein: Sie muss die beabsichtigte Semantik implementieren.
In Haskell (und C ++) können Sie die Semantik nicht angeben. In C ++ ist die Idee "Concepts" ungefähr ein Versuch, die Semantik anzunähern. In Felix können Sie die Absicht mit Axiomen, Reduktionen, Lemmas und Theoremen approximieren.
Der Haupt- und einzige Vorteil von (offenem) Überladen in einer Sprache mit guten Prinzipien wie Felix ist, dass es einfacher ist, sich Bibliotheksfunktionsnamen zu merken, sowohl für den Programmierer als auch für den Codeüberprüfer.
Der Hauptnachteil der Überladung ist der komplexe Algorithmus, der zur Implementierung erforderlich ist. Es passt auch nicht sehr gut zu Typinferenz: Obwohl die beiden nicht vollständig exklusiv sind, ist der Algorithmus, um beides zu tun, komplex genug, sodass der Programmierer die Ergebnisse wahrscheinlich nicht vorhersagen kann.
In C ++ ist dies auch ein Problem, da es einen schlampigen Matching-Algorithmus hat und auch automatische Typkonvertierungen unterstützt: In Felix habe ich dieses Problem "behoben", indem eine genaue Übereinstimmung und keine automatischen Typkonvertierungen erforderlich waren.
Ich denke, Sie haben die Wahl: Überladung oder Typinferenz. Inferenz ist nett, aber es ist auch sehr schwer, sie so zu implementieren, dass Konflikte richtig diagnostiziert werden. Ocaml teilt Ihnen beispielsweise mit, wo ein Konflikt erkannt wird, nicht jedoch, woher der erwartete Typ stammt.
Überladen ist nicht viel besser, selbst wenn Sie einen Qualitäts-Compiler haben, der versucht, Ihnen alle Kandidaten mitzuteilen. Es kann schwierig sein, zu erkennen, ob die Kandidaten polymorph sind, und noch schlimmer, wenn es sich um C ++ - Template-Hacker handelt.
quelle
Kommt auf den Kontext zurück, aber ich denke, Überladung macht eine Klasse viel nützlicher, wenn ich eine verwende, die von jemand anderem geschrieben wurde. Sie haben häufig weniger Redundanz.
quelle
Wenn Sie Benutzer haben möchten, die mit den Sprachen der C-Familie vertraut sind, sollten Sie dies tun, da Ihre Benutzer dies erwarten.
quelle