Perché un metodo che restituisce Unità può essere sovrascritto con il metodo che restituisce String quando i tipi restituiti non sono specificati in modo esplicito?


11

Stavo lavorando attraverso gli esempi di codice del capitolo Tratti nella programmazione in Scala Edition1 https://www.artima.com/pins1ed/traits.html

e ho riscontrato un comportamento strano a causa del mio errore di battitura. Mentre il metodo di un tratto di sotto frammento di codice override non dà alcun errore di compilazione, anche se il tipo di ritorno del metodo sovrascritto è diverso Unitvs String. Ma chiamando il metodo su un oggetto restituisce Unità ma non stampa nulla.

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 = ()

Ma quando do il tipo di ritorno esplicito nel metodo override, dà un errore di compilazione:

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

Qualcuno può aiutare a spiegare perché nessun errore di compilazione nel primo caso.


Il compilatore ha stampato un suggerimento valido per provare a sovrascrivere un metodo con un tipo di risultato diverso.
Andriy Plokhotnyuk,

Sì, certo, ma la mia domanda è: perché il compilatore ha superato il primo caso
Shanil,

1
Regola empirica, sii sempre esplicito sui tipi di ritorno_ (specialmente sulle API pubbliche) _. L'inferenza del tipo è ottima per le variabili locali, nient'altro.
Luis Miguel Mejía Suárez,

Risposte:



6

la mia domanda è: perché è arrivato attraverso il compilatore nel primo caso

Quando non è stato specificato esplicitamente il tipo restituito, è stato dedotto dal tipo che deve avere overrideaffinché funzioni.

Quello si è rivelato essere Unit.

Poiché è Stringpossibile assegnare valori (il valore dell'espressione che costituisce il corpo della funzione) Unit, il compilatore è felice.


1
Quello che voglio sapere ora, tuttavia, è il motivo per cui il tipo di ritorno esplicito è Stringstato rifiutato. In Java (e penso anche in Scala), ti è permesso restringere il tipo di ritorno quando esegui l'override. Ad esempio, quando viene restituito il metodo parent Number, è possibile restituire Integer. Forse void/ Unitè speciale.
Thilo,

1
Questo compila, ad esempio:trait Philosophical { def philosophize : Number = 1 } class Frog extends Philosophical { override def philosophize : Integer = 2 }
Thilo,

2
È possibile restringere il tipo restituito a un sottotipo; ma non puoi restringerlo a un tipo che può essere implicitamente convertito solo nel tipo restituito del metodo sovrascritto. Stringa Unitè più simile al secondo, anche se non è esattamente quello.
Alexey Romanov,

2
A livello di bytecode non esiste neanche un tipo di restituzione restrittivo, in realtà ci sono due metodi in Frog: def philosophize : Integere def philosophize : Number. Il secondo in realtà sovrascrive il Philosophicalmetodo di (e chiama il primo). Lo stesso potrebbe certamente essere fatto per void/ qualsiasi altra cosa, i designer hanno appena deciso di non farlo.
Alexey Romanov,

2
1. Java fa lo stesso. 2. Sì, in bytecode puoi farlo. Vedere ad esempio stackoverflow.com/questions/18655541/… e stackoverflow.com/questions/58065680/… .
Alexey Romanov,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.