Mengapa metode pengembalian Unit ditimpa dengan metode pengembalian String ketika jenis pengembalian tidak diberikan secara eksplisit?

11

Saya sedang mengerjakan contoh kode dari bab Traits in Programming in Scala Edition1 https://www.artima.com/pins1ed/traits.html

dan menemukan perilaku aneh karena kesalahan ketik saya. Sementara override metode sifat di bawah ini potongan kode tidak memberikan kesalahan kompilasi meskipun jenis kembalinya metode ditimpa berbeda Unitvs String. Tetapi setelah memanggil metode pada objek, ia mengembalikan Unit tetapi tidak mencetak apa pun.

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

Tetapi ketika saya memberikan tipe pengembalian eksplisit dalam metode yang diganti, itu memberikan kesalahan kompilasi:

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

Adakah yang bisa membantu menjelaskan mengapa tidak ada kesalahan kompilasi dalam kasus pertama.

Shanil
sumber
Compiler telah mencetak petunjuk yang valid bahwa Anda mencoba mengganti metode yang memiliki tipe hasil berbeda.
Andriy Plokhotnyuk
Ya memang, tapi pertanyaan saya adalah mengapa ia bisa melewati kompiler dalam kasus 1
Shanil
1
Rule of thumb, selalu eksplisit tentang return types_ (terutama pada API publik) _. Jenis inferensi sangat bagus untuk variabel lokal, tidak ada yang lain.
Luis Miguel Mejía Suárez

Jawaban:

8

Ketika jenis yang diharapkan adalah Unit, nilai apa pun dapat diterima :

Pembuangan Nilai

Jika ememiliki beberapa tipe nilai dan tipe yang diharapkan Unit, edikonversi ke tipe yang diharapkan dengan menyematkannya dalam term { e; () }.

Alexey Romanov
sumber
6

pertanyaan saya adalah mengapa bisa melalui kompiler dalam kasus 1

Ketika Anda tidak menentukan jenis pengembalian secara eksplisit itu disimpulkan oleh jenis itu perlu memiliki untuk overridebekerja.

Itu ternyata Unit.

Karena Stringnilai (nilai ekspresi yang membentuk fungsi tubuh) dapat ditugaskan Unit, kompiler senang.

Thilo
sumber
1
Apa yang ingin saya ketahui sekarang adalah mengapa tipe pengembalian eksplisit Stringditolak. Di Jawa (dan saya pikir dalam Scala, juga), Anda diizinkan untuk mempersempit tipe pengembalian saat menimpa. Misalnya, ketika metode induk kembali Number, Anda dapat kembali Integer. Mungkin void/ Unitkhusus.
Thilo
1
Ini mengkompilasi, misalnya:trait Philosophical { def philosophize : Number = 1 } class Frog extends Philosophical { override def philosophize : Integer = 2 }
Thilo
2
Anda dapat mempersempit jenis kembali ke subtipe; tetapi Anda tidak dapat mempersempitnya ke jenis yang hanya dapat secara implisit dikonversi ke jenis pengembalian metode yang diganti. Stringuntuk Unitlebih seperti yang kedua, bahkan jika itu tidak persis seperti itu.
Alexey Romanov
2
Pada level bytecode juga tidak ada tipe return yang menyempit, sebenarnya ada dua metode di Frog: def philosophize : Integerdan def philosophize : Number. Yang kedua sebenarnya mengesampingkan Philosophicalmetode (dan memanggil yang pertama). Hal yang sama pasti bisa dilakukan untuk void/ hal lain, para desainer hanya memutuskan untuk tidak melakukannya.
Alexey Romanov
2
1. Java melakukan hal yang sama. 2. Ya, dalam bytecode Anda bisa. Lihat misalnya stackoverflow.com/questions/18655541/… dan stackoverflow.com/questions/58065680/… .
Alexey Romanov