Pourquoi une méthode renvoyant Unit peut-elle être remplacée par une méthode renvoyant String alors que les types de retour ne sont pas explicitement indiqués?


11

Je travaillais sur les exemples de code du chapitre Traits in Programming in Scala Edition1 https://www.artima.com/pins1ed/traits.html

et est tombé sur un comportement étrange à cause de ma faute de frappe. Bien que la méthode de remplacement d'un trait sous l'extrait de code ne donne aucune erreur de compilation, bien que les types de retour de la méthode remplacée soient différents par Unitrapport à String. Mais en appelant la méthode sur un objet, elle renvoie Unit mais n'imprime rien.

trait Philosophical {
    def philosophize = println("I consume memory, therefore I am!")
}

class Frog extends Philosophical {
  override def toString = "green"
  override def philosophize = "It aint easy to be " + toString + "!"
}

val frog = new Frog
//frog: Frog = green

frog.philosophize
// no message printed on console

val f = frog.philosophize
//f: Unit = ()

Mais quand je donne le type de retour explicite dans la méthode surchargée, cela donne une erreur de compilation:

class Frog extends Philosophical {
  override def toString = "green"
  override def philosophize: String = "It aint easy to be " + toString + "!"
}
         override def philosophize: String = "It aint easy to be " + toString +
                      ^
On line 3: error: incompatible type in overriding
       def philosophize: Unit (defined in trait Philosophical);
        found   : => String
        required: => Unit

Quelqu'un peut-il aider à expliquer pourquoi aucune erreur de compilation dans le premier cas.


Le compilateur a imprimé un indice valide que vous essayez de remplacer une méthode qui a un type de résultat différent.
Andriy Plokhotnyuk

Oui en effet, mais ma question est de savoir pourquoi il est passé par le compilateur dans le 1er cas
Shanil

1
Règle générale, soyez toujours explicite sur les types de retour_ (en particulier sur les API publiques) _. L'inférence de type est idéale pour les variables locales, rien d'autre.
Luis Miguel Mejía Suárez

Réponses:



6

ma question est pourquoi il est passé par le compilateur dans le 1er cas

Lorsque vous n'avez pas spécifié explicitement le type de retour, cela a été déduit du type dont il a besoin pour que cela overridefonctionne.

Cela s'est avéré être Unit.

Puisque des Stringvaleurs (la valeur de l'expression constituant le corps de la fonction) peuvent être attribuées Unit, le compilateur est content.


1
Ce que je veux savoir maintenant, c'est pourquoi le type de retour explicite a Stringété rejeté. En Java (et je pense aussi à Scala), vous êtes autorisé à restreindre le type de retour lors de la substitution. Par exemple, lorsque la méthode parent revient Number, vous pouvez retourner Integer. Peut void- être / Unitest spécial.
Thilo

1
Cela compile, par exemple:trait Philosophical { def philosophize : Number = 1 } class Frog extends Philosophical { override def philosophize : Integer = 2 }
Thilo

2
Vous pouvez restreindre le type de retour à un sous-type; mais vous ne pouvez pas le restreindre à un type qui ne peut être implicitement converti qu'en type de retour de la méthode substituée. Stringto Unitressemble plus au second, même si ce n'est pas exactement ça.
Alexey Romanov

2
Au niveau du bytecode, il n'y a pas non plus de type de retour restreint, il y a en fait deux méthodes dans Frog: def philosophize : Integeret def philosophize : Number. La seconde remplace en fait la Philosophicalméthode de (et appelle la première). La même chose pourrait certainement être faite pour void/ n'importe quoi d'autre, les concepteurs ont juste décidé de ne pas le faire.
Alexey Romanov

2
1. Java fait de même. 2. Oui, en bytecode vous pouvez. Voir par exemple stackoverflow.com/questions/18655541/… et stackoverflow.com/questions/58065680/… .
Alexey Romanov
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.