Salah satu fitur yang saya lewatkan dari bahasa fungsional adalah gagasan bahwa operator hanyalah fungsi, jadi menambahkan operator khusus seringkali sesederhana menambahkan fungsi. Banyak bahasa prosedural memungkinkan operator kelebihan, jadi dalam beberapa hal operator masih berfungsi (ini sangat benar di D di mana operator dilewatkan sebagai string dalam parameter templat).
Tampaknya di mana operator kelebihan muatan diperbolehkan, seringkali sepele untuk menambahkan operator kustom tambahan. Saya menemukan posting blog ini , yang berpendapat bahwa operator kustom tidak bekerja dengan baik dengan notasi infiks karena aturan diutamakan, tetapi penulis memberikan beberapa solusi untuk masalah ini.
Saya melihat sekeliling dan tidak dapat menemukan bahasa prosedural yang mendukung operator khusus dalam bahasa tersebut. Ada peretasan (seperti makro di C ++), tapi itu hampir tidak sama dengan dukungan bahasa.
Karena fitur ini cukup sepele untuk diterapkan, mengapa tidak lebih umum?
Saya mengerti bahwa ini dapat menyebabkan beberapa kode jelek, tetapi itu tidak menghentikan desainer bahasa di masa lalu dari menambahkan fitur berguna yang dapat dengan mudah disalahgunakan (makro, operator ternary, pointer tidak aman).
Kasus penggunaan aktual:
- Terapkan operator yang hilang (mis. Lua tidak memiliki operator bitwise)
- Mimic D's
~
(array concatenation) - DSL
- Gunakan
|
sebagai gula sintaks gaya pipa Unix (menggunakan coroutine / generator)
Saya juga tertarik pada bahasa yang melakukan memungkinkan operator kustom, tapi aku lebih tertarik pada mengapa hal itu telah dikecualikan. Saya berpikir untuk membuat bahasa scripting untuk menambahkan operator yang ditentukan pengguna, tetapi berhenti sendiri ketika saya menyadari bahwa saya belum melihatnya di mana pun, jadi mungkin ada alasan bagus mengapa perancang bahasa lebih pintar daripada saya tidak mengizinkannya.
Jawaban:
Ada dua aliran pemikiran yang bertentangan secara diametris dalam desain bahasa pemrograman. Salah satunya adalah bahwa programmer menulis kode yang lebih baik dengan batasan lebih sedikit, dan yang lainnya adalah mereka menulis kode yang lebih baik dengan lebih banyak batasan. Menurut pendapat saya, kenyataannya adalah bahwa programmer berpengalaman yang baik berkembang dengan pembatasan lebih sedikit, tetapi pembatasan itu dapat menguntungkan kualitas kode pemula.
Operator yang ditentukan pengguna dapat membuat kode yang sangat elegan di tangan yang berpengalaman, dan kode yang benar-benar buruk oleh pemula. Jadi apakah bahasa Anda termasuk atau tidak tergantung pada sekolah pemikiran perancang bahasa Anda.
sumber
Format
metode) dan kapan harus menolak ( misalnya argumen tinju otomatis keReferenceEquals
). Semakin banyak kemampuan yang diberikan oleh pemrogram untuk mengatakan kapan kesimpulan tertentu tidak tepat, semakin aman dapat menawarkan kesimpulan yang nyaman bila perlu.Diberi pilihan antara array array dengan ~ atau dengan "myArray.Concat (secondArray)", saya mungkin lebih suka yang terakhir. Mengapa? Karena ~ adalah karakter yang sama sekali tidak berarti yang hanya memiliki maknanya - yaitu array concatenation - yang diberikan dalam proyek spesifik di mana ia ditulis.
Pada dasarnya, seperti yang Anda katakan, operator tidak berbeda dengan metode. Tetapi sementara metode dapat diberikan nama-nama yang dapat dibaca dan dipahami yang menambah pemahaman tentang aliran kode, operator tidak jelas dan situasional.
Inilah sebabnya saya juga tidak suka
.
operator PHP (penggabungan string) atau sebagian besar operator di Haskell atau OCaml, meskipun dalam kasus ini, beberapa standar yang diterima secara universal muncul untuk bahasa fungsional.sumber
+
dan<<
tentu saja tidak didefinisikan padaObject
(saya mendapatkan "tidak cocok untuk operator + di ..." ketika melakukan itu pada kelas telanjang di C ++).Premis Anda salah. Ini bukan "cukup sepele untuk diterapkan". Bahkan, ia membawa sekantong masalah.
Mari kita lihat "solusi" yang disarankan di pos:
Secara keseluruhan, ini adalah fitur yang mahal untuk diimplementasikan, baik dalam hal kompleksitas parser dan dalam hal kinerja, dan tidak jelas bahwa itu akan membawa banyak manfaat. Tentu, ada beberapa manfaat untuk kemampuan mendefinisikan operator baru tetapi bahkan mereka yang suka bertengkar (lihat saja jawaban lain dengan alasan bahwa memiliki operator baru bukanlah hal yang baik).
sumber
Mari kita abaikan seluruh argumen "operator disalahgunakan untuk merusak keterbacaan", dan fokus pada implikasi desain bahasa.
Operator infix memiliki lebih banyak masalah daripada aturan presedensi sederhana (meskipun untuk menjadi tumpul, tautan yang Anda referensi meremehkan dampak dari keputusan desain itu). Salah satunya adalah resolusi konflik: apa yang terjadi ketika Anda mendefinisikan
a.operator+(b)
danb.operator+(a)
? Memilih satu di atas yang lain mengarah pada melanggar properti komutatif yang diharapkan dari operator itu. Melempar kesalahan dapat menyebabkan modul yang bisa berfungsi menjadi rusak sekali bersama-sama. Apa yang terjadi ketika Anda mulai melemparkan jenis turunan ke dalam campuran?Faktanya adalah bahwa operator tidak hanya berfungsi. Fungsi berdiri sendiri atau dimiliki oleh kelasnya, yang memberikan preferensi yang jelas pada parameter mana (jika ada) yang memiliki pengiriman polimorfik.
Dan itu mengabaikan berbagai masalah pengemasan dan resolusi yang muncul dari operator. Alasan perancang bahasa (pada umumnya) membatasi definisi operator infiks adalah karena ia menciptakan setumpuk masalah untuk bahasa sambil memberikan manfaat yang dapat diperdebatkan.
Dan terus terang, karena mereka tidak sepele untuk diterapkan.
sumber
+
adalah kejahatan. Tetapi apakah ini benar-benar argumen terhadap operator yang ditentukan pengguna? Sepertinya argumen terhadap operator overloading secara umum.boost::spirit
. Segera setelah Anda mengizinkan operator yang ditetapkan pengguna yang menjadi lebih buruk karena tidak ada cara yang baik untuk bahkan menentukan prioritas matematika. Saya telah menulis sedikit tentang hal itu sendiri dalam konteks bahasa yang secara khusus terlihat untuk mengatasi masalah dengan operator yang ditentukan secara sewenang-wenang.Saya pikir Anda akan terkejut seberapa sering operator overloads yang diimplementasikan dalam beberapa bentuk. Tetapi mereka tidak umum digunakan di banyak komunitas.
Mengapa menggunakan ~ untuk menyatukan ke array? Mengapa tidak menggunakan << seperti yang dilakukan Ruby ? Karena programmer yang bekerja dengan Anda mungkin bukan programmer Ruby. Atau programmer D. Jadi apa yang mereka lakukan ketika mereka menemukan kode Anda? Mereka harus pergi dan mencari apa arti simbol itu.
Saya dulu bekerja dengan pengembang C # yang sangat baik yang juga memiliki selera bahasa fungsional. Tiba-tiba, ia mulai memperkenalkan monad ke C # dengan cara metode ekstensi dan menggunakan terminologi monad standar. Tidak ada yang bisa membantah bahwa beberapa kodenya lebih singkat dan bahkan lebih mudah dibaca setelah Anda tahu artinya, tetapi itu berarti bahwa setiap orang harus mempelajari terminologi monad sebelum kodenya masuk akal .
Cukup adil, menurut Anda? Itu hanya tim kecil. Secara pribadi, saya tidak setuju. Setiap pengembang baru ditakdirkan untuk bingung dengan terminologi ini. Apakah kita tidak memiliki cukup masalah dalam mempelajari domain baru?
Di sisi lain, saya dengan senang hati akan menggunakan satu
??
operator yang di C # karena saya mengharapkan lain C # pengembang untuk tahu apa itu, tapi aku tidak akan membebani menjadi bahasa yang tidak mendukung secara default.sumber
??
contoh Anda .Saya dapat memikirkan beberapa alasan:
O(1)
. Tetapi dengan overloading operator,someobject[i]
bisa dengan mudah menjadiO(n)
operasi tergantung pada implementasi operator pengindeksan.Pada kenyataannya, ada sangat sedikit kasus di mana kelebihan beban operator memiliki penggunaan yang dapat dibenarkan dibandingkan dengan hanya menggunakan fungsi biasa. Contoh yang sah mungkin merancang kelas bilangan kompleks untuk digunakan oleh matematikawan, yang memahami cara-cara yang dipahami dengan baik bahwa operator matematika didefinisikan untuk bilangan kompleks. Tapi ini sebenarnya bukan kasus yang sangat umum.
Beberapa kasus menarik untuk dipertimbangkan:
+
hanya fungsi biasa. Anda dapat menentukan fungsi sesuka Anda (biasanya ada cara mendefinisikannya dalam ruang nama terpisah untuk menghindari konflik dengan bawaan+
), termasuk operator. Tetapi ada kecenderungan budaya untuk menggunakan nama fungsi yang bermakna, jadi ini tidak banyak disalahgunakan. Selain itu, dalam notasi awalan Lisp cenderung digunakan secara eksklusif, sehingga nilai "sintaksis gula" yang disediakan operator lebih sedikit.cout << "Hello World!"
siapa pun?) Tetapi pendekatan itu masuk akal mengingat posisi C ++ sebagai bahasa kompleks yang memungkinkan pemrograman tingkat tinggi sambil tetap memungkinkan Anda untuk menjadi sangat dekat dengan logam untuk kinerja, sehingga Anda dapat misalnya menulis kelas bilangan kompleks yang berperilaku persis seperti yang Anda inginkan tanpa mengorbankan kinerja. Dipahami bahwa itu adalah tanggung jawab Anda sendiri jika Anda menembak diri sendiri.sumber
Itu tidak sepele untuk diterapkan (kecuali diterapkan secara sepele). Ini juga tidak membuat Anda banyak, bahkan jika diimplementasikan secara ideal: keuntungan keterbacaan dari kesederhanaan diimbangi oleh kerugian keterbacaan dari ketidaktahuan dan opacity. Singkatnya, ini tidak biasa karena biasanya tidak sepadan dengan waktu pengembang atau pengguna.
Yang mengatakan, saya dapat memikirkan tiga bahasa yang melakukannya, dan mereka melakukannya dengan cara yang berbeda:
sumber
Salah satu alasan utama operator kustom tidak disarankan adalah karena setiap operator dapat berarti / dapat melakukan apa saja.
Misalnya
cstream
banyak shift kiri yang terlalu banyak dikritik.Ketika suatu bahasa memungkinkan operator kelebihan beban, umumnya ada dorongan untuk menjaga perilaku operator serupa dengan perilaku dasar untuk menghindari kebingungan.
Juga operator yang ditentukan pengguna membuat penguraian jauh lebih sulit, terutama ketika ada juga aturan preferensi khusus.
sumber
+
tambahkan dua hal,-
kurangi,*
gandakan. Perasaan saya adalah bahwa tidak ada yang memaksa programmer untuk membuat fungsi / metodeadd
benar-benar menambahkan apa pun dandoNothing
dapat meluncurkan nuklir. Dana.plus(b.minus(c.times(d)).times(e)
itu jauh lebih mudah dibacaa + (b - c * d) * e
(bonus tambahan - di mana sengatan pertama adalah kesalahan dalam transkripsi). Saya tidak melihat bagaimana yang pertama lebih bermakna ...Kami tidak menggunakan operator yang ditentukan pengguna karena alasan yang sama kami tidak menggunakan kata-kata yang ditentukan pengguna. Tidak ada yang akan menyebut fungsi mereka "sworp". Satu-satunya cara untuk menyampaikan pemikiran Anda kepada orang lain adalah menggunakan bahasa bersama. Dan itu berarti kata-kata dan tanda (operator) harus diketahui oleh masyarakat untuk siapa Anda menulis kode Anda.
Oleh karena itu operator yang Anda lihat digunakan dalam bahasa pemrograman adalah yang telah kami ajarkan di sekolah (aritmatika) atau yang telah ditetapkan dalam komunitas pemrograman, seperti operator boolean.
sumber
elem
adalah ide bagus dan tentu saja semua operator harus mengerti, tetapi yang lain tampaknya tidak setuju.Adapun bahasa yang mendukung overloading seperti itu: Scala melakukannya, sebenarnya dengan cara yang jauh lebih bersih dan lebih baik C ++. Sebagian besar karakter dapat digunakan dalam nama fungsi, sehingga Anda dapat mendefinisikan operator seperti! + * = ++, jika Anda mau. Ada dukungan bawaan untuk infix (untuk semua fungsi yang mengambil satu argumen). Saya pikir Anda dapat menentukan asosiatif fungsi tersebut juga. Namun Anda tidak dapat menentukan prioritas (hanya dengan trik jelek, lihat di sini ).
sumber
Satu hal yang belum disebutkan adalah kasus Smalltalk, di mana semuanya (termasuk operator) mengirim pesan. "Operator" suka
+
,|
dan sebagainya sebenarnya metode unary.Semua metode dapat diganti, jadi
a + b
berarti penambahan bilangan bulat jikaa
danb
keduanya bilangan bulat, dan berarti penambahan vektor jika keduanyaOrderedCollection
s.Tidak ada aturan prioritas, karena ini hanya pemanggilan metode. Ini memiliki implikasi penting untuk notasi matematika standar:
3 + 4 * 5
berarti(3 + 4) * 5
, tidak3 + (4 * 5)
.(Ini adalah batu sandungan utama bagi para pemula Smalltalk. Melanggar aturan matematika menghilangkan kasus khusus, sehingga semua evaluasi kode berlangsung seragam dari kiri ke kanan, membuat bahasa yang jauh lebih sederhana.)
sumber
Anda berjuang melawan dua hal di sini:
Dalam sebagian besar bahasa, operator tidak benar-benar diimplementasikan sebagai fungsi sederhana. Mereka mungkin memiliki beberapa fungsi scaffolding, tetapi compiler / runtime secara eksplisit menyadari makna semantik mereka dan bagaimana menerjemahkannya secara efisien ke dalam kode mesin. Ini jauh lebih benar bahkan dibandingkan dengan fungsi built-in (itulah sebabnya sebagian besar implementasi juga tidak menyertakan semua overhead panggilan fungsi dalam implementasinya). Sebagian besar operator adalah abstraksi level yang lebih tinggi pada instruksi primitif yang ditemukan dalam CPU (yang sebagian alasan mengapa sebagian besar operator adalah aritmatika, boolean, atau bitwise). Anda dapat memodelkannya sebagai fungsi "khusus" (menyebutnya "primitif" atau "builtin" atau "asli" atau apa pun), tetapi untuk melakukan itu secara umum memerlukan serangkaian semantik yang sangat kuat untuk mendefinisikan fungsi khusus tersebut. Alternatifnya adalah memiliki operator built-in yang secara semantik terlihat seperti operator yang ditentukan pengguna, tetapi sebaliknya memanggil jalur khusus dalam kompiler. Itu bertentangan dengan jawaban untuk pertanyaan kedua ...
Selain masalah terjemahan mesin yang saya sebutkan di atas, pada level sintaksis operator tidak terlalu berbeda dari fungsi. Mereka membedakan karakteristik cenderung bahwa mereka singkat dan simbolis, yang mengisyaratkan karakteristik tambahan signifikan mereka harus berguna: mereka harus memiliki makna yang luas dipahami / semantik untuk pengembang. Simbol-simbol pendek tidak membawa banyak makna kecuali jika itu adalah tangan pendek untuk seperangkat semantik yang sudah dipahami. Itu membuat operator yang ditetapkan pengguna secara inheren tidak membantu, karena sifatnya mereka tidak begitu dipahami secara luas. Mereka masuk akal sebanyak satu atau dua nama fungsi huruf.
Kelebihan operator C ++ menyediakan lahan subur untuk memeriksa hal ini. Sebagian besar "penyalahgunaan" operator kelebihan datang dalam bentuk kelebihan yang mematahkan beberapa kontrak semantik yang dipahami secara luas (contoh klasik adalah kelebihan operator + sehingga a + b! = B + a, atau di mana + memodifikasi salah satu dari nya operan).
Jika Anda melihat Smalltalk, yang memungkinkan operator overloading dan operator yang ditentukan pengguna, Anda dapat melihat bagaimana suatu bahasa bisa melakukannya, dan seberapa bermanfaatnya. Dalam Smalltalk, operator hanyalah metode dengan sifat sintaksis yang berbeda (yaitu, mereka dikodekan sebagai infix binary). Bahasa ini menggunakan "metode primitif" untuk operator dan metode khusus yang dipercepat. Anda menemukan bahwa sedikit jika ada operator yang ditentukan pengguna dibuat, dan ketika mereka, mereka cenderung tidak terbiasa sebanyak penulis mungkin dimaksudkan untuk mereka untuk digunakan. Bahkan ekivalen dari kelebihan operator jarang terjadi, karena sebagian besar merupakan kerugian bersih untuk mendefinisikan fungsi baru sebagai operator alih-alih metode, karena yang terakhir memungkinkan untuk ekspresi semantik fungsi.
sumber
Saya selalu menemukan kelebihan operator di C ++ menjadi jalan pintas yang nyaman untuk tim pengembang tunggal, tetapi yang menyebabkan semua jenis kebingungan dalam jangka panjang hanya karena panggilan metode sedang "disembunyikan" dengan cara yang tidak mudah. untuk alat seperti doxygen untuk dipisahkan, dan orang-orang perlu memahami idiom untuk memanfaatkannya dengan benar.
Kadang-kadang jauh lebih sulit untuk dimengerti daripada yang Anda harapkan, bahkan. Sekali waktu, dalam proyek C ++ lintas-platform besar saya memutuskan itu akan menjadi ide yang baik untuk menormalkan cara jalur dibangun dengan membuat
FilePath
objek (mirip dengan objek JavaFile
), yang akan memiliki operator / digunakan untuk menggabungkan yang lain bagian jalan di atasnya (sehingga Anda dapat melakukan sesuatu sepertiFile::getHomeDir()/"foo"/"bar"
dan itu akan melakukan hal yang benar pada semua platform yang didukung kami). Setiap orang yang melihatnya pada dasarnya akan berkata, "Apa-apaan ini? Pembagian tali? ... Oh, itu lucu, tapi saya tidak percaya untuk melakukan hal yang benar."Demikian pula, ada banyak kasus dalam pemrograman grafis atau bidang lain di mana matematika vektor / matriks banyak terjadi di mana ia tergoda untuk melakukan hal-hal seperti Matriks * Matriks, Vektor * Vektor (titik), Vektor% Vektor (lintas), Matriks * Vektor ( matrix transform), Matrix ^ Vector (transformasi matriks kasus khusus mengabaikan koordinat homogen - berguna untuk normals permukaan), dan seterusnya, tetapi sementara itu menghemat sedikit waktu penguraian untuk orang yang menulis perpustakaan matematika vektor, itu hanya berakhir Facebook membingungkan masalah lebih untuk orang lain. Itu tidak layak.
sumber
Kelebihan operator adalah ide yang buruk karena alasan yang sama bahwa kelebihan metode adalah ide yang buruk: simbol yang sama pada layar akan memiliki arti yang berbeda tergantung pada apa yang ada di sekitarnya. Ini membuatnya lebih sulit untuk membaca santai.
Karena keterbacaan adalah aspek penting dari pemeliharaan, Anda harus selalu menghindari kelebihan muatan (kecuali dalam beberapa kasus yang sangat khusus). Jauh lebih baik bagi setiap simbol (apakah operator atau pengidentifikasi alfanumerik) untuk memiliki makna unik yang berdiri sendiri.
Sebagai ilustrasi: saat membaca kode asing, jika Anda menemukan pengidentifikasi alfanumerik baru yang tidak Anda ketahui, setidaknya Anda memiliki keuntungan yang Anda tahu tidak tahu.. Anda kemudian dapat mencarinya. Namun, jika Anda melihat pengidentifikasi umum atau operator yang Anda tahu artinya, Anda jauh lebih kecil kemungkinannya untuk menyadari bahwa itu sebenarnya telah kelebihan beban untuk memiliki makna yang sama sekali berbeda. Untuk mengetahui operator apa yang kelebihan beban (dalam basis kode yang membuat penggunaan berlebihan kelebihan muatan), Anda akan membutuhkan pengetahuan tentang kode yang lengkap, bahkan jika Anda hanya ingin membaca sebagian kecil darinya. Ini akan menyulitkan pengembang baru untuk mempercepat kode itu, dan tidak mungkin membawa orang untuk pekerjaan kecil. Ini mungkin baik untuk keamanan pekerjaan programmer, tetapi jika Anda bertanggung jawab atas keberhasilan basis kode, Anda harus menghindari praktik ini dengan cara apa pun.
Karena operator berukuran kecil, operator yang kelebihan muatan akan memungkinkan lebih banyak kode padat, tetapi membuat kode padat bukan manfaat nyata. Satu baris dengan logika dua kali lebih lama untuk dibaca. Kompiler tidak peduli. Satu-satunya masalah adalah keterbacaan manusia. Karena membuat kode yang ringkas tidak meningkatkan keterbacaan, tidak ada manfaat nyata untuk kekompakan. Silakan mengambil ruang, dan memberikan operasi unik pengidentifikasi unik, dan kode Anda akan lebih sukses dalam jangka panjang.
sumber
Kesulitan teknis untuk menangani prioritas dan penguraian kompleks dikesampingkan, saya pikir ada beberapa aspek dari apa bahasa pemrograman yang harus dipertimbangkan.
Operator biasanya adalah konstruksi logis pendek yang didefinisikan dengan baik dan didokumentasikan dalam bahasa inti (bandingkan, tetapkan ..). Mereka juga biasanya sulit dimengerti tanpa dokumentasi (bandingkan
a^b
denganxor(a,b)
misalnya). Ada sejumlah operator yang agak terbatas yang sebenarnya mungkin masuk akal dalam pemrograman normal (>, <, =, + dll.).Gagasan saya adalah lebih baik tetap menggunakan sekumpulan operator yang terdefinisi dengan baik dalam suatu bahasa - kemudian mengizinkan operator kelebihan dari operator tersebut (diberi rekomendasi lembut bahwa operator harus melakukan hal yang sama, tetapi dengan tipe data khusus).
Kasus penggunaan Anda
~
dan|
akan benar-benar dimungkinkan dengan overloading operator sederhana (C #, C ++, dll.). DSL adalah area penggunaan yang valid, tetapi mungkin satu-satunya area yang valid (dari sudut pandang saya). Namun, saya berpikir bahwa ada alat yang lebih baik untuk membuat bahasa baru di dalamnya. Menjalankan bahasa DSL sejati dalam bahasa lain tidak sulit dengan menggunakan alat kompiler-kompiler mana pun. Hal yang sama berlaku untuk "memperpanjang argumen LUA". Suatu bahasa kemungkinan besar didefinisikan terutama untuk menyelesaikan masalah dengan cara tertentu, bukan menjadi dasar untuk sub-bahasa (ada pengecualian).sumber
Faktor lain untuk itu adalah tidak selalu mudah untuk mendefinisikan operasi dengan operator yang tersedia. Maksud saya, ya, untuk jenis angka apa pun, operator '*' dapat masuk akal, dan biasanya diimplementasikan dalam bahasa atau dalam modul yang ada. Tetapi dalam kasus kelas kompleks tipikal yang Anda perlu mendefinisikan (hal-hal seperti ShipingAddress, WindowManager, ObjectDimensions, PlayerCharacter, dll) bahwa perilaku tidak jelas ... Apa artinya menambah atau mengurangi nomor ke Alamat? Lipat gandakan dua Alamat?
Tentu, Anda dapat menentukan bahwa menambahkan string ke kelas ShippingAddress berarti operasi kustom seperti "ganti baris 1 di alamat" (bukan fungsi "setLine1") dan menambahkan nomor adalah "ganti kode pos" (alih-alih "setZipCode") , tapi kemudian kodenya tidak terlalu mudah dibaca dan membingungkan. Kami biasanya berpikir bahwa operator digunakan dalam tipe / kelas dasar, karena perilakunya intuitif, jelas dan konsisten (setidaknya setelah Anda terbiasa dengan bahasa tersebut). Pikirkan tipe-tipe seperti Integer, String, ComplexNumber, dll.
Jadi, bahkan jika mendefinisikan operator bisa sangat berguna dalam beberapa kasus tertentu, implementasi dunia nyata mereka sangat terbatas, karena 99% dari kasus di mana itu akan menjadi kemenangan yang jelas sudah diimplementasikan dalam paket bahasa dasar.
sumber