Warum rät Jorge Ortiz, eine Überlastung der Methoden zu vermeiden?
Antworten:
Ü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
UPDATE 3
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...
_.foo
Problems 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.
addIntToDouble
, addDoubleToInt
dh 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.
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 x
könnte ändern, welche foo
Methode aufgerufen wird. Der Wert von x
muss 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.
foo
sollte 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.
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.