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.