Warum „Methodenüberladung vermeiden“?

78

Warum rät Jorge Ortiz, eine Überlastung der Methoden zu vermeiden?

fehlender Faktor
quelle
Könnte es etwas damit zu tun haben, dass Scala Javas Typlöschung erbt?
Justin Niessner
1
@ Justin: Was hat Typlöschung damit zu tun?
fehlender Faktor
6
Warum fragst du Jorge Ortiz nicht, warum er von einer Überlastung der Methoden abrät?
John
Ich bin mir nicht sicher, ob es anwendbar ist, da ich Jorges ursprüngliche Absicht nicht kenne, aber: michid.wordpress.com/2008/02/08/…
Justin Niessner
12
bah ... bit.ly/aduyIn : '(
fehlender Faktor

Antworten:

108

Überladen macht es etwas schwieriger, eine Methode auf eine Funktion zu heben:

object A {
   def foo(a: Int) = 0
   def foo(b: Boolean) = 0
   def foo(a: Int, b: Int) = 0

   val function = foo _ // fails, must use = foo(_, _) or (a: Int) => foo(a)
}

Sie können eine einer Reihe überladener Methoden nicht selektiv importieren.

Es besteht eine größere Wahrscheinlichkeit, dass Mehrdeutigkeiten auftreten, wenn versucht wird, implizite Ansichten anzuwenden, um die Argumente an die Parametertypen anzupassen:

scala> implicit def S2B(s: String) = !s.isEmpty                             
S2B: (s: String)Boolean

scala> implicit def S2I(s: String) = s.length                               
S2I: (s: String)Int

scala> object test { def foo(a: Int) = 0; def foo(b: Boolean) = 1; foo("") }
<console>:15: error: ambiguous reference to overloaded definition,
both method foo in object test of type (b: Boolean)Int
and  method foo in object test of type (a: Int)Int
match argument types (java.lang.String)
       object test { def foo(a: Int) = 0; def foo(b: Boolean) = 1; foo("") }

Es kann Standardparameter leise unbrauchbar machen:

object test { 
    def foo(a: Int) = 0; 
    def foo(a: Int, b: Int = 0) = 1 
}

Individuell zwingen Sie diese Gründe nicht dazu, eine Überlastung vollständig zu vermeiden. Ich habe das Gefühl, dass mir einige größere Probleme fehlen.

AKTUALISIEREN

Die Beweise häufen sich.

UPDATE 2

  • Sie können (derzeit) keine überladenen Methoden in Paketobjekten verwenden.
  • Anwendbarkeitsfehler sind für Anrufer Ihrer API schwerer zu diagnostizieren .

UPDATE 3

  • Die statische Überlastungsauflösung kann eine API aller Arten von Sicherheit berauben:
scala> object O { def apply[T](ts: T*) = (); def apply(f: (String => Int)) = () }
defined object O

scala> O((i: String) => f(i)) // oops, I meant to call the second overload but someone changed the return type of `f` when I wasn't looking...
Retronym
quelle
2
Derzeit gibt es auch einen Fehler in Scalac, der in bestimmten Fällen durch Überlastung ausgelöst wird. Issues.scala-lang.org/browse/SI-7596 .
Cvogt
2
Die ersten beiden Probleme betreffen nicht jede gültige Verwendung von Überladung. Einen Fehlerbericht für die 3. Ausgabe eingereicht . Die Einschränkung der Standardeinstellungen ist freiwillig und könnte theoretisch behoben werden. Der Fehler des _.fooProblems ist Scalas begrenzte Typinferenz, nicht Überladung. Sie beantworten die Frage, aber einige der Gründe sind auf andere Schwächen in Scala zurückzuführen, die verbessert werden könnten. Überladen ist effizienter als das Herunterladen einer Disjunktion zur Laufzeit, oder ein kartesisches Produkt von Namen ist verrauscht und trennt sich von einer gemeinsamen Semantik.
Shelby Moore III
3
Typklassen können derzeit aufgrund des Fehlens eines erstklassigen Unionstyps nicht allgemein verwendet werden . Ja, ich sehe diese Einstellung in Scalas Community, stelle mir aber stattdessen vor addIntToDouble, addDoubleToIntdh ein kartesisches Produkt von Namen anstelle einer statischen Typisierung für jede gängige Semantik. Das Ersetzen der Eingabe durch die Benennung scheint regressiv zu sein. Java hat mehr Dinge richtig gemacht, als wir vielleicht erkennen.
Shelby Moore III
2
Ich schrieb im Diskussionsthread (für den Fehlerbericht, den ich im vorherigen Kommentar erwähnt habe): "Was böse ist, erwartet IMO, dass Überladung das ist, was es nicht ist, oder dass es weniger wichtig ist, einen Namen für eine gemeinsame Semantik zu haben."
Shelby Moore III
2
Die Antwort und die Kommentare erscheinen mir sehr naiv und erwähnen nicht den wichtigsten Grund für die Verwendung von Überladung: Wenn eine Methode tatsächlich eine sehr unterschiedliche interne Logik ausführen muss, abhängig von den an sie übergebenen Typen. Die Antwort von "use implicits" schlägt sofort fehl, da möglicherweise keine mögliche Konvertierung von einem Objekt in einen anderen Typ existiert, der die spezielle Logik verkörpert.
ely
8

Die Gründe, die Gilad und Jason (Retronym) angeben, sind allesamt sehr gute Gründe, um eine Überlastung nach Möglichkeit zu vermeiden. Gilads Gründe konzentrieren sich darauf, warum Überladung im Allgemeinen problematisch ist, während sich Jasons Gründe darauf konzentrieren, warum es im Kontext anderer Scala-Funktionen problematisch ist.

Zu Jasons Liste möchte ich hinzufügen, dass Überladung schlecht mit Typinferenz interagiert. Erwägen:

val x = ...
foo(x)

Eine Änderung des abgeleiteten Typs von xkönnte ändern, welche fooMethode aufgerufen wird. Der Wert von xmuss sich nicht ändern, nur der abgeleitete Typ von x, der aus allen möglichen Gründen auftreten kann.

Aus all den genannten Gründen (und ein paar weiteren, die ich sicher vergesse) denke ich, dass das Überladen von Methoden so sparsam wie möglich eingesetzt werden sollte.

Jorge Ortiz
quelle
2
Wenn Sie dies nicht möchten, deklarieren Sie den Typ für x. Wenn Sie es nicht deklarieren, sagen Sie, dass Sie möchten, dass es sich ändert. Die Semantik von foosollte für jede Überladung mit der gleichen Anzahl von Parametern gleich sein, sonst wurde sie falsch entworfen. Um den Umfang der bizarren Kaskade von Inferenzänderungen einzuschränken, sollten öffentliche Methoden immer ihre Rückgabetypen deklarieren. Ich denke, dies war eines der Probleme, die sich auf die Scala-Binärkompatibilität zwischen Versionen auswirken.
Shelby Moore III
1

Ich denke, der Rat ist nicht speziell für Scala gedacht, sondern für OO im Allgemeinen (soweit ich weiß, soll Scala ein Best-of-Breed zwischen OO und Functional sein).

Überschreiben ist in Ordnung, es ist das Herzstück des Polymorphismus und spielt eine zentrale Rolle im OO-Design.

Überlastung ist dagegen problematischer. Bei der Überladung von Methoden ist es schwer zu erkennen, welche Methode wirklich aufgerufen wird, und dies ist in der Tat häufig eine Quelle der Verwirrung. Es gibt auch selten eine Rechtfertigung dafür, warum eine Überlastung wirklich notwendig ist. Das Problem kann meistens auf andere Weise gelöst werden, und ich stimme zu, dass Überladung ein Geruch ist.

Hier ist ein Artikel , der gut erklärt, was ich mit "Überladung ist eine Quelle der Verwirrung" meine, was meiner Meinung nach der Hauptgrund ist, warum es entmutigt wird. Es ist für Java, aber ich denke, es gilt auch für Scala.

ewernli
quelle
2
Und Scala ist sowieso nicht in erster Linie eine OO-Sprache.
Daniel Earwicker
4
@ewenli - Jorge ist in der Scala-Community bekannt und der von Rahul bereitgestellte Link war einer von Jorges Scala-Tipps. Ihre Antwort hat jedoch nichts zu bieten, warum Überladung speziell für Scala schlecht ist , was eindeutig die Absicht der Frage war. Ich habe auch keine Ahnung, warum Sie entschieden haben, dass die Frage in irgendeiner Weise verwirrt war - Sie sollten dies einfach aus Ihrer Antwort entfernen, da es völlig ungerechtfertigt ist. -1
oxbow_lakes
6
@ Daniel Scala ist in erster Linie eine OO-Sprache. Gibt es einen Grund, warum Sie das nicht glauben würden?
Daniel C. Sobral
3
Oh, der Schöpfer einer konkurrierenden funktionalen Sprache glaubt nicht, dass Scala funktional genug ist! Großer Schock! :)
Daniel Earwicker
3
@ Daniel Scala mag ein Multi-Paradigma sein, aber es ist immer noch hauptsächlich eine objektorientierte Sprache. Die Funktionsmerkmale von Scala werden als objektorientierte Merkmale implementiert . Selbst das funktionalste Scala-Programm besteht ausschließlich aus Objekten und ihren jeweiligen Klassen und Merkmalen. Nun mag Martin Odersky sagen, was er über seine Sprache will (es ist schließlich seine Sprache), aber in einer streng technischen Bewertung ist Scala in erster Linie objektorientiert, wobei ich mit "hauptsächlich" meine, dass alles andere auf dieser Eigenschaft aufbaut .
Daniel C. Sobral