Anda memiliki sudut pandang yang baik tentang masalah ini di sini:
Tujuan
Percakapan Tipe Sistem Scala dengan Martin Odersky, Bagian III
oleh Bill Venners dan Frank Sommers (18 Mei 2009)
Pembaruan (Oktober2009): apa yang berikut di bawah ini sebenarnya telah diilustrasikan dalam artikel baru ini oleh Bill Venners:
Anggota Tipe Abstrak versus Parameter Tipe Generik dalam Scala (lihat ringkasan di bagian akhir)
(Berikut adalah kutipan relevan dari wawancara pertama, Mei 2009, penekanan saya)
Prinsip umum
Selalu ada dua gagasan abstraksi:
- parameterisasi dan
- anggota abstrak.
Di Jawa Anda juga memiliki keduanya, tetapi itu tergantung pada apa yang Anda abstraksi.
Di Jawa Anda memiliki metode abstrak, tetapi Anda tidak bisa meneruskan metode sebagai parameter.
Anda tidak memiliki bidang abstrak, tetapi Anda bisa meneruskan nilai sebagai parameter.
Dan juga Anda tidak memiliki anggota tipe abstrak, tetapi Anda dapat menentukan tipe sebagai parameter.
Jadi di Jawa Anda juga memiliki ketiganya, tetapi ada perbedaan tentang prinsip abstraksi apa yang dapat Anda gunakan untuk hal-hal apa. Dan Anda bisa berpendapat bahwa perbedaan ini cukup sewenang-wenang.
Jalan Scala
Kami memutuskan untuk memiliki prinsip konstruksi yang sama untuk ketiga jenis anggota .
Jadi Anda bisa memiliki bidang abstrak serta parameter nilai.
Anda dapat melewatkan metode (atau "fungsi") sebagai parameter, atau Anda dapat abstrak darinya.
Anda dapat menentukan jenis sebagai parameter, atau Anda bisa abstrak di atasnya.
Dan apa yang kita dapatkan secara konseptual adalah bahwa kita dapat memodelkan satu dalam hal yang lain. Setidaknya pada prinsipnya, kita dapat mengekspresikan setiap jenis parameterisasi sebagai bentuk abstraksi berorientasi objek. Jadi bisa dibilang Scala adalah bahasa yang lebih orthogonal dan lengkap.
Mengapa?
Apa, khususnya, jenis abstrak yang membeli Anda adalah perawatan yang bagus untuk masalah kovarian yang telah kita bicarakan sebelumnya.
Satu masalah standar, yang sudah ada sejak lama, adalah masalah hewan dan makanan.
Teka-teki adalah memiliki kelas Animal
dengan metode eat
,, yang memakan makanan.
Masalahnya adalah jika kita subkelas Hewan dan memiliki kelas seperti Sapi, maka mereka akan makan hanya Rumput dan bukan makanan sembarangan. Seekor Sapi tidak bisa makan Ikan, misalnya.
Yang Anda inginkan adalah dapat mengatakan bahwa seekor sapi memiliki metode makan yang hanya memakan rumput dan bukan hal-hal lain.
Sebenarnya, Anda tidak dapat melakukan itu di Jawa karena ternyata Anda dapat membangun situasi yang tidak sehat, seperti masalah menetapkan Buah ke variabel Apple yang saya bicarakan sebelumnya.
Jawabannya adalah Anda menambahkan tipe abstrak ke dalam kelas Animal .
Anda berkata, kelas Hewan baru saya memiliki jenis SuitableFood
, yang saya tidak tahu.
Jadi ini tipe abstrak. Anda tidak memberikan implementasi jenis itu. Maka Anda memiliki eat
metode yang hanya makan SuitableFood
.
Dan kemudian di Cow
kelas saya akan berkata, OK, saya punya Sapi, yang memperpanjang kelas Animal
, dan untuk Cow type SuitableFood equals Grass
.
Jadi tipe abstrak memberikan gagasan tentang tipe dalam superclass yang saya tidak tahu, yang kemudian saya isi kemudian dengan subkelas dengan sesuatu yang saya tahu .
Sama dengan parameterisasi?
Memang bisa. Anda bisa mengukur hewan kelas dengan jenis makanan yang dimakannya.
Tetapi dalam praktiknya, ketika Anda melakukannya dengan banyak hal yang berbeda, itu mengarah pada ledakan parameter , dan biasanya, terlebih lagi, dalam batas parameter .
Pada ECOOP 1998, Kim Bruce, Phil Wadler, dan saya memiliki sebuah makalah di mana kami menunjukkan bahwa ketika Anda meningkatkan jumlah hal yang tidak Anda ketahui, program tipikal akan tumbuh secara kuadrat .
Jadi ada alasan yang sangat bagus untuk tidak melakukan parameter, tetapi untuk memiliki anggota abstrak ini, karena mereka tidak memberi Anda ledakan kuadratik ini.
thatismatt bertanya dalam komentar:
Apakah Anda pikir yang berikut ini adalah ringkasan yang adil:
- Tipe Abstrak digunakan dalam hubungan 'has-a' atau 'uses-a' (misalnya a
Cow eats Grass
)
- di mana sebagai obat generik biasanya 'dari' hubungan (misalnya
List of Ints
)
Saya tidak yakin hubungannya berbeda antara menggunakan tipe abstrak atau generik. Yang berbeda adalah:
- bagaimana mereka digunakan, dan
- bagaimana batas parameter dikelola.
Untuk memahami apa yang dibicarakan Martin tentang "ledakan parameter, dan biasanya, terlebih lagi, dalam batas parameter ", dan pertumbuhan kuadratik berikutnya ketika tipe abstrak dimodelkan menggunakan generik, Anda dapat mempertimbangkan makalah " Abstraksi Komponen yang Dapat Diukur " "ditulis oleh ... Martin Odersky, dan Matthias Zenger untuk OOPSLA 2005, dirujuk dalam publikasi proyek Palcom (selesai pada 2007).
Ekstrak yang relevan
Definisi
Anggota tipe abstrak menyediakan cara yang fleksibel untuk abstrak dibandingkan jenis komponen beton.
Tipe abstrak dapat menyembunyikan informasi tentang internal komponen, mirip dengan penggunaannya dalam tanda tangan SML . Dalam kerangka kerja berorientasi objek di mana kelas dapat diperluas dengan pewarisan, mereka juga dapat digunakan sebagai sarana parameterisasi yang fleksibel (sering disebut polimorfisme keluarga, lihat entri weblog ini misalnya , dan makalah yang ditulis oleh Eric Ernst ).
(Catatan: Polimorfisme keluarga telah diusulkan untuk bahasa yang berorientasi objek sebagai solusi untuk mendukung kelas rekursif yang dapat digunakan kembali namun aman jenisnya.
Gagasan utama polimorfisme keluarga adalah gagasan keluarga, yang digunakan untuk mengelompokkan kelas yang saling rekursif)
abstraksi tipe terbatas
abstract class MaxCell extends AbsCell {
type T <: Ordered { type O = T }
def setMax(x: T) = if (get < x) set(x)
}
Di sini, deklarasi tipe T dibatasi oleh batas tipe atas yang terdiri dari nama kelas Dipesan dan penyempurnaan { type O = T }
.
Membatasi batas atas spesialisasi T di subclass dengan yang subtipe dari Memerintahkan dimana anggota jenis O
dari equals T
.
Karena kendala ini, <
metode class Ordered dijamin berlaku untuk penerima dan argumen tipe T.
Contoh menunjukkan bahwa anggota tipe terikat itu sendiri dapat muncul sebagai bagian dari batas.
(yaitu Scala mendukung polimorfisme terbatas-F )
(Catatan, dari Peter Canning, William Cook, Walter Hill, makalah Walter Olthoff:
Kuantifikasi terbatas diperkenalkan oleh Cardelli dan Wegner sebagai alat untuk mengetik fungsi yang beroperasi secara seragam pada semua subtipe dari jenis tertentu.
Mereka mendefinisikan model "objek" sederhana. dan menggunakan kuantifikasi terbatas untuk fungsi pemeriksaan tipe yang masuk akal pada semua objek yang memiliki set "atribut" tertentu.
Presentasi yang lebih realistis dari bahasa berorientasi objek akan memungkinkan objek yang merupakan elemen dari tipe yang didefinisikan secara rekursif .
Dalam konteks ini, dibatasi kuantifikasi tidak lagi memenuhi tujuannya, mudah untuk menemukan fungsi yang masuk akal pada semua objek yang memiliki serangkaian metode tertentu, tetapi yang tidak dapat diketik dalam sistem Cardelli-Wegner.
Untuk memberikan dasar untuk fungsi polimorfik yang diketik dalam bahasa berorientasi objek, kami memperkenalkan kuantifikasi terikat-F)
Dua wajah dari koin yang sama
Ada dua bentuk utama abstraksi dalam bahasa pemrograman:
- parameterisasi dan
- anggota abstrak.
Bentuk pertama adalah tipikal untuk bahasa fungsional, sedangkan bentuk kedua biasanya digunakan dalam bahasa berorientasi objek.
Secara tradisional, Java mendukung parameterisasi untuk nilai, dan abstraksi anggota untuk operasi. Java 5.0 yang lebih baru dengan generik mendukung parameterisasi juga untuk tipe.
Argumen untuk menyertakan obat generik dalam Scala ada dua:
Pertama, pengkodean menjadi tipe abstrak tidak mudah dilakukan dengan tangan. Selain kerugian dalam keringkasan, ada juga masalah konflik nama yang tidak disengaja antara nama tipe abstrak yang meniru parameter tipe.
Kedua, generik dan tipe abstrak biasanya memiliki peran berbeda dalam program Scala.
- Generik biasanya digunakan ketika seseorang hanya perlu mengetikkan contoh , sedangkan
- tipe abstrak biasanya digunakan ketika seseorang perlu merujuk ke tipe abstrak dari kode klien .
Yang terakhir muncul khususnya dalam dua situasi:
- Seseorang mungkin ingin menyembunyikan definisi yang tepat dari anggota tipe dari kode klien, untuk mendapatkan semacam enkapsulasi yang diketahui dari sistem modul SML-style.
- Atau seseorang mungkin ingin menimpa tipe kovarian dalam subclass untuk mendapatkan polimorfisme keluarga.
Dalam sistem dengan polimorfisme terbatas, menulis ulang tipe abstrak menjadi generik mungkin memerlukan ekspansi kuadrat dari tipe bound .
Perbarui Oktober 2009
Abstrak Anggota Tipe versus Parameter Tipe Generik dalam Scala (Bill Venners)
(penekanan milikku)
Pengamatan saya sejauh ini tentang anggota tipe abstrak adalah bahwa mereka terutama merupakan pilihan yang lebih baik daripada parameter tipe umum ketika:
- Anda ingin orang-orang bercampur dalam definisi tipe-tipe itu melalui ciri-ciri .
- Anda berpikir penyebutan nama anggota tipe secara eksplisit ketika sedang didefinisikan akan membantu pembacaan kode .
Contoh:
jika Anda ingin melewatkan tiga objek fixture yang berbeda ke dalam tes, Anda dapat melakukannya, tetapi Anda harus menentukan tiga jenis, satu untuk setiap parameter. Jadi seandainya saya mengambil pendekatan parameter type, kelas-kelas suite Anda mungkin berakhir seperti ini:
// Type parameter version
class MySuite extends FixtureSuite3[StringBuilder, ListBuffer, Stack] with MyHandyFixture {
// ...
}
Sedangkan dengan pendekatan tipe anggota akan terlihat seperti ini:
// Type member version
class MySuite extends FixtureSuite3 with MyHandyFixture {
// ...
}
Satu perbedaan kecil lainnya antara anggota tipe abstrak dan parameter tipe generik adalah bahwa ketika parameter tipe generik ditentukan, pembaca kode tidak melihat nama parameter tipe. Demikianlah seseorang untuk melihat baris kode ini:
// Type parameter version
class MySuite extends FixtureSuite[StringBuilder] with StringBuilderFixture {
// ...
}
Mereka tidak akan tahu apa nama parameter tipe yang ditentukan sebagai StringBuilder tanpa mencarinya. Sedangkan nama parameter tipe ada di sana dalam kode dalam pendekatan anggota tipe abstrak:
// Type member version
class MySuite extends FixtureSuite with StringBuilderFixture {
type FixtureParam = StringBuilder
// ...
}
Dalam kasus terakhir, pembaca kode dapat melihat bahwa itu StringBuilder
adalah tipe "parameter fixture".
Mereka masih perlu mencari tahu apa yang dimaksud dengan "parameter fixture", tetapi mereka setidaknya bisa mendapatkan nama tipe tanpa melihat dalam dokumentasi.
Saya memiliki pertanyaan yang sama ketika saya membaca tentang Scala.
Keuntungan menggunakan obat generik adalah Anda membuat keluarga jenis. Tak seorang pun akan perlu subclass
Buffer
-mereka hanya dapat menggunakanBuffer[Any]
,Buffer[String]
, dllJika Anda menggunakan tipe abstrak, maka orang-orang akan dipaksa untuk membuat subkelas. Orang akan membutuhkan kelas seperti
AnyBuffer
,StringBuffer
, dllAnda perlu memutuskan mana yang lebih baik untuk kebutuhan khusus Anda.
sumber
Buffer { type T <: String }
atauBuffer { type T = String }
tergantung pada kebutuhan AndaAnda dapat menggunakan tipe abstrak bersama dengan parameter tipe untuk membuat templat kustom.
Mari kita asumsikan Anda perlu membuat pola dengan tiga sifat yang terhubung:
dengan cara argumen yang disebutkan dalam parameter tipe adalah AA, BB, CC itu sendiri dengan hormat
Anda dapat datang dengan beberapa jenis kode:
yang tidak akan bekerja dengan cara sederhana ini karena jenis ikatan parameter. Anda harus menjadikannya kovarian untuk mewarisi dengan benar
Sampel yang satu ini akan dikompilasi tetapi menetapkan persyaratan kuat pada aturan varians dan tidak dapat digunakan dalam beberapa kesempatan
Compiler akan keberatan dengan banyak kesalahan pemeriksaan varians
Dalam hal ini, Anda dapat mengumpulkan semua persyaratan tipe dalam sifat tambahan dan menetapkan sifat-sifat lain di atasnya
Sekarang kita dapat menulis representasi konkret untuk pola yang dijelaskan, mendefinisikan metode kiri dan bergabung di semua kelas dan dapatkan benar dan gandakan secara gratis
Jadi, tipe dan parameter tipe abstrak digunakan untuk membuat abstraksi. Keduanya memiliki kelebihan dan kekurangan. Tipe abstrak lebih spesifik dan mampu menggambarkan struktur tipe apa pun tetapi verbose dan perlu ditentukan secara eksplisit. Ketik parameter dapat membuat banyak jenis secara instan tetapi memberi Anda kekhawatiran tambahan tentang pewarisan dan mengetik batas.
Mereka memberikan sinergi satu sama lain dan dapat digunakan bersama untuk membuat abstraksi kompleks yang tidak dapat diungkapkan hanya dengan satu di antaranya.
sumber
Saya pikir tidak ada banyak perbedaan di sini. Tipe anggota abstrak dapat dilihat sebagai tipe eksistensial yang mirip dengan tipe rekaman dalam beberapa bahasa fungsional lainnya.
Sebagai contoh, kami memiliki:
dan
Maka
ListT
sama saja denganList[_]
. Keyakinan anggota tipe adalah bahwa kita dapat menggunakan kelas tanpa tipe konkret eksplisit dan menghindari terlalu banyak parameter tipe.sumber