Question

Je vais avoir la compréhension d'un petit problème variance des méthodes en cas de surcharge.

Bien que cela fonctionne parfaitement à cause de covariance dans le type de retour

class Bla 
class Fasel extends Bla 

trait Test[A] {
 def tester(): Bla = new Bla
}

class FooTest[A](a: A) extends Test[A] {
 override def tester(): Fasel = new Fasel                                      
}

celui-ci échoue même si les fonctions sont contravariant dans leur types de paramètres.

class Bla 
class Fasel extends Bla 

trait Test[A] {
 def tester(a: Fasel): Bla = new Bla                                           
}

class FooTest[A](a: A) extends Test[A] {
 override def tester(a: Bla): Fasel = new Fasel
}

Qu'est-ce que j'obtiens mal ici? Tous les pointeurs?

Cordialement, raichoo

Était-ce utile?

La solution

Il y a deux choses qui se passent ici:

  1. Fonction A et une méthode ne sont pas la même chose
  2. méthodes ne sont pas polymorphes dans les types de leurs paramètres

Votre méthode tester est une méthode, pas Function1 . Il peut être soulevé dans une fonction en utilisant la syntaxe underscore:

val f = (new FooTest[String]).tester _ // Fasel => Bla

Cette fonction sera contre-variante dans son type d'entrée. (Il vaut la peine de dire, cependant, que les fonctions ne peuvent pas être paramétrés et aussi à dire que je devais avoir une instance de Foo ou FooTest afin d'obtenir un objet de fonction pour la méthode de tester. Bien sûr, suit de la première observation!)

Une fonction est un objet, il ne peut pas être surchargée que cela n'a pas de sens. Les méthodes peuvent être remplacées. Cependant, comme je le dis plus haut, la suppression est pas polymorphes dans les types de paramètres de la méthode. Ainsi, par exemple:

class A {
  def foo(a : Any) = println("A: " + a)
}

class B extends A {
  override def foo(s : String) = println("B " + s) //will not compile!
}

Les deux méthodes dans mon exemple ci-dessus a deux méthodes distinctes:. Dispatch dynamique fonctionne uniquement sur la cible de procédé (à savoir l'objet sur lequel il est appelé)

Dans ce qui précède, par exemple, si vous supprimez la déclaration de override, le code compilé. Si vous exécutez la commande suivante:

(new B).foo(1)   //prints A 1
(new B).foo("s") //prints B s

En effet, bien que les deux méthodes sont appelées foo, ce sont des méthodes complètement différentes (à savoir que j'ai surchargée foo, pas surchargée il). Il est mieux comprise comme étant que les arguments d'une méthode (y compris leurs types) font partie des uniques de cette méthode nom . Une méthode annule une autre que si elles ont exactement la même nom .


Essentiellement, vous avez confondu ce sont deux séparés et liés non les choses dans votre question, que je POSER pour plus de clarté:

  • Les annotations de la variance sur Function1 définir ce que cela signifie pour une fonction d'être un sous-type d'une autre (et donc assignable à une référence d'un type donné).
  • Les méthodes peuvent être remplacées sur les sous-classes et les grandes lignes de spécification du langage des règles lorsque ce lieu primordial a.

Autres conseils

Les extraits pertinents de la spécification:

types de méthode

  

Un type de procédé est désigné en interne comme (Ps)U, où (Ps) est une séquence de noms de paramètres et de types (p1 :T1,...,pn :Tn) pour certains n≥0 et U est un type (valeur ou méthode). Ce type représente mentionné des méthodes qui prennent des arguments nommés p1, ..., pn des types T1,...,Tn et que le retour d'un résultat de type U.

     

types de méthode n'existent pas que les types de valeurs. Si un nom de méthode est utilisée en tant que valeur, son type est implicitement converti en un type de fonction correspondant (§6.26).

Redéfinition

  

Un membre M de C de classe matchs (§5.1.3) un élément non-privé M′ d'une classe de base de C est dit pour remplacer ce membre. Dans ce cas, la liaison de l'organe remplaçant doit M subsumer (§3.5.2) la liaison du M′ membre surchargée.

Conformance

  

Si Ti ≡ Ti′ pour i = 1, ..., n et de conforme à U U′ puis le type de méthode (p1 : T1,...,pn :Tn)U est conforme à (p1′ :T1′,...,pn′ :Tn′)U′.

subsume

  

Une déclaration ou une définition dans un certain type de composé de C de type classe subsume une autre déclaration du même nom dans certains si l'une des cales suivant le type de composé ou type de classe C′,.

     
      
  • Une déclaration de valeur ou de définition qui définit un nom x de type T englobe une déclaration de valeur ou une méthode qui définit avec le type x T′, à condition T <: T′.
  •   

Vous pouvez modifier et changer le type de retour à un sous-type, mais tout en acceptant supertype pour argument satisfaire le principe de substitution, il est interdit (ce qui est tout comme en java) La raison est que vous pouvez également les méthodes de surcharge (plusieurs méthodes avec le même nom, les différents arguments comptent et types) et votre méthode sera considerered une surcharge. Je suppose que cela est principalement une question de compatibilité JVM et d'avoir une spécification raisonnable. Fait déjà la surcharge spec scala assez compliqué. routage simplement la méthode surchargée à une surcharge avec la signature modifiée pourrait être assez bon:

class FooTest[A] extends Test[A] {
   override def test(a: Fasel) : Fasel = test(a.asInstanceOf[Bla])
   def test(a: Bla) : Fasel = new Fasel
}

Ce que vous pouvez faire est un paramètre de type contravariant, fourni en apparaît uniquement en position contravariante (simplifier, apparaît comme type d'argument et non comme type de résultat), mais il est tout à fait différent:

trait Test[-A] {
  // note the - before A. 
  // You might want to constraint with -A >: Fasel
  def tester(a: A) : Bla = new Bla
}

class FooTest extends Test[Bla] {
  override def tester(a: Bla): Fasel = new Fasel
}

val testOfBla: Test[Bla] = new FooTest
val testOfFasel: Test[Fasel] = testOfBla 
  // you can assign a Test[Bla] to a test[Fasel] because of the -A

Eh bien dans votre deuxième exemple la signature de tester() dans Test déclare un argument Fasel mais avec la signature de FooTest surchargée tester() est déclarée avec un Bla comme argument. Depuis Fasel est un sous-type de Bla par leur hiérarchie extends c'est probablement faux.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top