Saya sedang mengembangkan bahasa yang dikompilasi secara statis dan sangat diketik, dan saya meninjau kembali gagasan apakah akan memasukkan kelebihan fungsi sebagai fitur bahasa. Saya menyadari bahwa saya sedikit bias, terutama berasal dari C[++|#]
latar belakang.
Apa argumen yang paling meyakinkan untuk dan menentang termasuk kelebihan fungsi dalam bahasa?
EDIT: Apakah tidak ada orang yang memiliki pendapat yang berlawanan?
Bertrand Meyer (pencipta Eiffel pada 1985/1986) menyebut metode overloading ini: (sumber)
mekanisme kesombongan yang tidak membawa apa pun pada kekuatan semantik bahasa OO, tetapi menghambat keterbacaan dan mempersulit tugas semua orang
Sekarang itu adalah generalisasi besar, tapi dia pria yang cerdas, jadi saya pikir aman untuk mengatakan dia bisa mendukungnya jika perlu. Bahkan, ia hampir membuat Brad Abrams (salah satu pengembang CLSv1) yakin bahwa .NET seharusnya tidak mendukung metode overloading. (sumber) Itu beberapa hal yang kuat. Adakah yang bisa menjelaskan pemikirannya, dan apakah sudut pandangnya masih bisa dibenarkan 25 tahun kemudian?
sumber
Saya sarankan setidaknya menyadari kelas tipe di Haskell. Kelas-kelas tipe diciptakan untuk menjadi pendekatan disiplin terhadap kelebihan beban operator, tetapi telah menemukan kegunaan lain, dan sampai batas tertentu, membuat Haskell seperti apa adanya.
Misalnya, berikut adalah contoh kelebihan ad-hoc (tidak cukup valid untuk Haskell):
Dan inilah contoh yang sama dari overloading dengan kelas tipe:
Sebuah Kelemahan dari ini adalah bahwa Anda harus datang dengan nama-nama yang funky untuk semua typeclasses Anda (seperti di Haskell, Anda memiliki lebih abstrak
Monad
,Functor
,Applicative
serta sederhana dan lebih dikenaliEq
,Num
danOrd
).Keuntungannya adalah, begitu Anda terbiasa dengan typeclass, Anda tahu cara menggunakan jenis apa pun di kelas itu. Plus, mudah untuk menjaga fungsi dari tipe yang tidak mengimplementasikan kelas yang diperlukan, seperti pada:
Sunting: Di Haskell, jika Anda menginginkan
==
operator yang menerima dua jenis berbeda, Anda bisa menggunakan kelas jenis multi-parameter:Tentu saja, ini mungkin ide yang buruk, karena secara eksplisit memungkinkan Anda membandingkan apel dan jeruk. Namun, Anda mungkin ingin mempertimbangkan hal ini
+
, karena menambahkan aWord8
keInt
benar - benar adalah hal yang masuk akal untuk dilakukan dalam beberapa konteks.sumber
(==) :: Int -> Float -> Bool
mana saja? (terlepas dari apakah itu ide yang bagus, tentu saja)class Eq a ...
diterjemahkan ke dalam pseudo-C-family akan menjadiinterface Eq<A> {bool operator==(A x, A y);}
, dan alih-alih menggunakan kode templated untuk membandingkan objek sewenang-wenang, Anda menggunakan 'antarmuka' ini. Apakah itu benar?==
berada di ruang nama yang berbeda tetapi tidak memungkinkan untuk menimpanya. Harap perhatikan bahwa ada satu namespace (Prelude
) yang disertakan secara default tetapi Anda dapat mencegah memuatnya dengan menggunakan ekstensi atau dengan mengimpornya secara eksplisit (tidakimport Prelude ()
akan mengimpor apa pun dariPrelude
danimport qualified Prelude as P
tidak akan memasukkan simbol ke namespace saat ini).Izinkan fungsi berlebihan, Anda tidak dapat melakukan hal berikut dengan parameter opsional (atau jika Anda bisa, tidak baik).
contoh sepele mengasumsikan tidak ada
base.ToString()
metodesumber
Saya selalu lebih suka parameter default daripada fungsi yang berlebihan. Fungsi kelebihan beban umumnya hanya memanggil versi "default" dengan parameter default. Kenapa menulis
Ketika saya bisa melakukan:
Yang mengatakan, saya menyadari kadang-kadang kelebihan fungsi melakukan hal-hal yang berbeda, daripada hanya memanggil varian lain dengan parameter default ... tetapi dalam kasus seperti itu, itu bukan ide yang buruk (pada kenyataannya, itu mungkin ide yang baik ) untuk hanya memberikannya nama yang berbeda.
(Juga, argumen kata kunci gaya Python bekerja sangat baik dengan parameter default.)
sumber
Array Slice(int start, int length) {...}
kelebihan bebanArray Slice(int start) {return this.Slice(start, this.Count - start);}
? Itu tidak bisa dikodekan menggunakan parameter default. Apakah Anda pikir mereka harus diberi nama yang berbeda? Jika demikian, bagaimana Anda memberi nama mereka?indexOf(char ch)
+indexOf(Date dt)
pada daftar. Saya suka nilai default juga, tetapi tidak bisa ditukar dengan pengetikan statis.Anda baru saja menggambarkan Java. Atau C #.
Mengapa Anda menemukan kembali kemudi?
Pastikan bahwa tipe pengembalian adalah bagian dari tanda tangan metode danOverload ke isi hati Anda, itu benar-benar membersihkan kode ketika Anda tidak perlu mengatakannya.sumber
EnumX.Flag1 | Flag2 | Flag3
. Saya tidak akan mengimplementasikan ini, meskipun. Jika saya melakukannya dan jenis kembali tidak digunakan, saya akan mencari jenis kembalivoid
.Grrr .. belum cukup privilege untuk berkomentar ..
@Mason Wheeler: Waspadalah terhadap Ada, yang melakukan overload pada tipe kembali. Juga bahasa saya Felix melakukannya juga dalam beberapa konteks, khususnya, ketika suatu fungsi mengembalikan fungsi lain dan ada panggilan seperti:
tipe b dapat digunakan untuk resolusi kelebihan beban. C ++ juga kelebihan pada tipe pengembalian dalam beberapa keadaan:
Bahkan ada algoritma untuk overloading pada tipe kembali, menggunakan inferensi tipe. Sebenarnya tidak terlalu sulit untuk dilakukan dengan mesin, masalahnya adalah manusia merasa sulit. (Saya pikir garis besarnya diberikan dalam Buku Naga, algoritma ini disebut algoritma lihat-lihat jika saya ingat dengan benar)
sumber
Kegunaan terhadap implementasi fungsi overloading: 25 metode yang dinamai seperti itu melakukan hal yang sama tetapi dengan set argumen yang sangat berbeda dalam berbagai pola.
Use-case terhadap tidak menerapkan fungsi overloading: 5 metode yang bernama sama dengan set tipe yang sangat mirip dalam pola yang sama persis.
Pada akhirnya, saya tidak sabar untuk membaca dokumen untuk API yang diproduksi dalam kedua kasus tersebut.
Tetapi dalam satu kasus ini tentang apa yang mungkin dilakukan pengguna. Dalam kasus lain itu yang harus dilakukan pengguna karena pembatasan bahasa. IMO, lebih baik untuk setidaknya memungkinkan kemungkinan penulis program cukup pintar untuk membebani secara masuk akal tanpa menciptakan ambiguitas. Ketika Anda menampar tangan dan mengambil opsi itu, pada dasarnya Anda menjamin ambiguitas akan terjadi. Saya lebih tentang mempercayai pengguna untuk melakukan hal yang benar daripada menganggap mereka akan selalu melakukan hal yang salah. Dalam pengalaman saya, proteksionisme cenderung mengarah pada perilaku yang bahkan lebih buruk dari komunitas bahasa.
sumber
Saya memilih untuk memberikan kelas tipe-overloading dan multi-tipe biasa dalam bahasa saya, Felix.
Saya menganggap (terbuka) kelebihan beban penting, terutama dalam bahasa yang banyak jenis numeriknya (Felix memiliki semua tipe numerik C). Namun tidak seperti C ++ yang menyalahgunakan kelebihan dengan membuat templat bergantung padanya, Felix polimorfisme adalah parametrik: Anda perlu kelebihan muatan untuk templat di C ++ karena templat di C ++ dirancang dengan buruk.
Kelas tipe disediakan di Felix juga. Bagi mereka yang tahu C ++ tetapi tidak grok Haskell, abaikan mereka yang menggambarkannya sebagai overloading. Ini bukan seperti overloading, melainkan seperti spesialisasi templat: Anda mendeklarasikan templat yang tidak Anda terapkan, lalu memberikan implementasi untuk kasus-kasus tertentu sesuai kebutuhan Anda. Pengetikan bersifat parametrik polimorfik, implementasinya adalah dengan instantiasi ad hoc tetapi tidak dimaksudkan untuk tidak dibatasi: ia harus mengimplementasikan semantik yang dimaksud.
Di Haskell (dan C ++) Anda tidak bisa menyatakan semantiknya. Dalam C ++ ide "Konsep" kira-kira merupakan upaya untuk mendekati semantik. Dalam Felix, Anda dapat memperkirakan maksud dengan aksioma, reduksi, lemma, dan teorema.
Keuntungan utama, dan satu - satunya kelebihan (terbuka) dalam bahasa berprinsip baik seperti Felix adalah membuatnya lebih mudah untuk mengingat nama fungsi pustaka, baik untuk penulis program dan untuk peninjau kode.
Kerugian utama dari kelebihan beban adalah algoritma kompleks yang diperlukan untuk mengimplementasikannya. Itu juga tidak cocok dengan inferensi tipe: meskipun keduanya tidak sepenuhnya eksklusif, algoritma untuk melakukan keduanya cukup kompleks, pemrogram mungkin tidak akan dapat memprediksi hasilnya.
Dalam C ++ ini juga masalah karena memiliki algoritma pencocokan ceroboh dan juga mendukung konversi tipe otomatis: di Felix I "memperbaiki" masalah ini dengan memerlukan pencocokan yang tepat dan tidak ada konversi tipe otomatis.
Jadi Anda punya pilihan saya pikir: overloading atau ketik inferensi. Inferensi itu lucu, tetapi juga sangat sulit untuk diterapkan dengan cara yang mendiagnosis konflik dengan benar. Ocaml, misalnya, memberi tahu Anda di mana ia mendeteksi konflik, tetapi tidak dari mana ia menyimpulkan tipe yang diharapkan.
Overloading tidak jauh lebih baik, bahkan jika Anda memiliki kompiler berkualitas yang mencoba memberi tahu Anda semua kandidat, mungkin sulit dibaca jika kandidatnya polimorfik, dan lebih buruk lagi jika itu adalah peretas template C ++.
sumber
Turun ke konteks, tapi saya pikir kelebihan membuat kelas jauh lebih berguna ketika saya menggunakan satu yang ditulis oleh orang lain. Anda sering berakhir dengan redundansi yang lebih sedikit.
sumber
Jika Anda ingin memiliki pengguna yang terbiasa dengan bahasa C-family maka ya Anda harus melakukannya karena pengguna Anda akan mengharapkannya.
sumber