web-dev-qa-db-fra.com

Pourquoi "éviter la surcharge de méthode"?

75
missingfaktor

La surcharge rend un peu plus difficile le transfert d'une méthode vers une fonction:

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)
}

Vous ne pouvez pas importer de manière sélective l'une d'un ensemble de méthodes surchargées.

Il y a de plus grandes chances qu'une ambiguïté survienne lorsque vous essayez d'appliquer des vues implicites pour adapter les arguments aux types de paramètres:

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("") }

Il peut tranquillement rendre les paramètres par défaut inutilisables:

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

Individuellement, ces raisons ne vous obligent pas à éviter complètement la surcharge. J'ai l'impression de manquer de gros problèmes.

[~ # ~] mise à jour [~ # ~]

Les preuves s'accumulent.

MISE À JOUR 2

  • Vous ne pouvez pas (actuellement) utiliser des méthodes surchargées dans les objets de package.
  • Les erreurs d'applicabilité sont plus difficiles à diagnostiquer pour les appelants de votre API.

MISE À JOUR 3

  • la résolution de surcharge statique peut priver une API de toute sécurité de type:
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...
104
retronym

Les raisons invoquées par Gilad et Jason (rétronyme) sont toutes de très bonnes raisons pour éviter la surcharge si possible. Les raisons de Gilad se concentrent sur les raisons pour lesquelles la surcharge est problématique en général, tandis que les raisons de Jason se concentrent sur les raisons pour lesquelles cela pose problème dans le contexte d'autres fonctionnalités Scala.

À la liste de Jason, j'ajouterais que la surcharge interagit mal avec l'inférence de type. Considérer:

val x = ...
foo(x)

Un changement dans le type inféré de x pourrait modifier la méthode foo qui sera appelée. La valeur de x n'a pas besoin de changer, juste le type déduit de x, ce qui peut se produire pour toutes sortes de raisons.

Pour toutes les raisons données (et quelques autres je suis sûr que j'oublie), je pense que la surcharge de méthode devrait être utilisée avec le moins de précaution possible.

8
Jorge Ortiz

Je pense que le conseil n'est pas destiné à scala en particulier, mais à OO en général (jusqu'à présent, je sais scala is censé être le meilleur de la race entre OO et fonctionnel).

Remplacer est très bien, c'est le cœur du polymorphisme et est au cœur de la conception OO.

La surcharge en revanche est plus problématique. Avec la surcharge de méthode, il est difficile de discerner quelle méthode sera vraiment invoquée et c'est en effet souvent une source de confusion. Il y a aussi rarement une justification pour laquelle la surcharge est vraiment nécessaire. Le problème peut la plupart du temps être résolu d'une autre manière et je conviens que la surcharge est une odeur.

Voici n article qui explique bien ce que je veux dire par "la surcharge est une source de confusion", ce qui, je pense, est la principale raison pour laquelle cela est découragé. C'est pour Java mais je pense que cela s'applique également à scala.

1
ewernli