¿Por qué Jorge Ortiz aconseja evitar la sobrecarga de métodos?
Respuestas:
La sobrecarga hace que sea un poco más difícil elevar un método a una función:
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)
}
No puede importar selectivamente uno de un conjunto de métodos sobrecargados.
Existe una mayor probabilidad de que surja ambigüedad al intentar aplicar vistas implícitas para adaptar los argumentos a los tipos de parámetros:
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("") }
Puede inutilizar silenciosamente los parámetros predeterminados:
object test {
def foo(a: Int) = 0;
def foo(a: Int, b: Int = 0) = 1
}
Individualmente, estas razones no lo obligan a evitar por completo la sobrecarga. Siento que me estoy perdiendo algunos problemas mayores.
ACTUALIZAR
La evidencia se está acumulando.
ACTUALIZACIÓN 2
ACTUALIZACIÓN 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
problema es la inferencia de tipo limitada de Scala, no la sobrecarga. Responde a la pregunta, pero algunas de las razones se deben a otras debilidades en Scala que podrían mejorarse. La sobrecarga es más eficiente que el tiempo de ejecución rebajando una disyunción, o que un producto cartesiano de nombres es ruidoso y se desconecta de una semántica compartida.
addIntToDouble
, addDoubleToInt
es decir, un producto cartesiano de nombres en lugar de tipos estáticos para cada semántica común. Reemplazar la mecanografía con la denominación parece ser regresivo. Java hizo más cosas correctas de las que quizás reconocemos.
Las razones que dan Gilad y Jason (retronym) son muy buenas razones para evitar la sobrecarga si es posible. Las razones de Gilad se centran en por qué la sobrecarga es problemática en general, mientras que las razones de Jason se centran en por qué es problemática en el contexto de otras características de Scala.
A la lista de Jason, agregaría que la sobrecarga interactúa mal con la inferencia de tipos. Considerar:
val x = ...
foo(x)
Un cambio en el tipo inferido de x
podría alterar el foo
método que se llama. El valor de x
no tiene por qué cambiar, solo el tipo inferido de x
, lo que podría suceder por todo tipo de razones.
Por todas las razones dadas (y algunas más, estoy seguro de que las olvido), creo que la sobrecarga de métodos debe usarse con la menor moderación posible.
foo
debería ser la misma para cada sobrecarga con el mismo número de parámetros, de lo contrario, se diseñó incorrectamente. En cuanto a limitar el alcance de la extraña cascada de cambios de inferencia, los métodos públicos siempre deben declarar sus tipos de retorno. Creo que este fue uno de los problemas que afectaron la compatibilidad binaria de Scala entre versiones.
Creo que el consejo no está destinado especialmente a scala, sino a OO en general (hasta ahora sé que se supone que scala es el mejor de su clase entre OO y funcional).
La anulación está bien, es el corazón del polimorfismo y es fundamental para el diseño OO.
La sobrecarga, por otro lado, es más problemática. Con la sobrecarga de métodos, es difícil discernir qué método se invocará realmente y, de hecho, con frecuencia es una fuente de confusión. Rara vez existe una justificación de por qué la sobrecarga es realmente necesaria. La mayoría de las veces, el problema se puede resolver de otra manera y estoy de acuerdo en que la sobrecarga es un olor.
Aquí hay un artículo que explica muy bien lo que quiero decir con "la sobrecarga es una fuente de confusión", que creo que es la razón principal por la que se desaconseja. Es para Java, pero creo que también se aplica a Scala.