Ini agak subyektif, tapi saya berharap untuk mendapatkan pemahaman yang lebih jelas tentang faktor-faktor apa yang membuat operator jelas untuk menggunakan vs tumpul dan sulit. Saya telah mempertimbangkan desain bahasa baru-baru ini, dan satu masalah yang selalu saya lingkari adalah kapan membuat operasi kunci dalam bahasa menjadi operator, dan kapan harus menggunakan kata kunci atau fungsi.
Haskell agak terkenal karena hal ini, karena operator khusus mudah dibuat dan sering kali tipe data baru akan dipaket dengan beberapa operator untuk digunakan. Perpustakaan Parsec, misalnya, hadir dengan banyak operator untuk menggabungkan parser bersama, dengan permata seperti >.
dan .>
saya bahkan tidak dapat mengingat apa artinya saat ini, tetapi saya ingat mereka sangat mudah untuk dikerjakan setelah saya hafal apa sebenarnya maksud mereka. Apakah panggilan fungsi seperti leftCompose(parser1, parser2)
lebih baik? Tentu saja lebih bertele-tele, tetapi dalam beberapa hal lebih jelas.
Kelebihan operator dalam bahasa mirip-C adalah masalah yang sama, tetapi diperbesar oleh masalah tambahan yaitu pemuatan yang berlebihan dari operator yang dikenal seperti +
dengan makna baru yang tidak biasa.
Dalam bahasa baru apa pun, ini akan tampak seperti masalah yang cukup sulit. Dalam F #, misalnya, casting menggunakan operator tipe-casting yang diturunkan secara matematis, alih-alih sintaks cor gaya C # atau gaya VB verbose. C #: (int32) x
VB: CType(x, int32)
F #:x :> int32
Secara teori, bahasa baru dapat memiliki operator untuk sebagian besar fungsi bawaan. Alih-alih def
atau dec
atau var
untuk deklarasi variabel, mengapa tidak ! name
atau @ name
atau yang serupa. Ini tentu saja mempersingkat deklarasi diikuti dengan mengikat: @x := 5
bukan declare x = 5
atau let x = 5
Kebanyakan kode akan membutuhkan banyak definisi variabel, jadi mengapa tidak?
Kapan operator jelas dan berguna, dan kapan itu mengaburkan?
sumber
+
untuk penggabungan string atau<<
untuk stream). Dengan Haskell, di sisi lain, operator dapat berupa fungsi dengan nama khusus (yaitu, tidak kelebihan beban) atau bagian dari kelas tipe yang berarti bahwa sementara itu polimorfik, ia melakukan hal logis yang sama untuk setiap jenis, dan bahkan memiliki tipe tanda tangan yang sama. Begitu>>
juga>>
untuk setiap tipe dan tidak akan pernah sedikit berubah.Jawaban:
dari sudut pandang desain bahasa umum tidak perlu ada perbedaan antara fungsi dan operator. Orang bisa menggambarkan fungsi sebagai operasi awalan dengan arity (atau bahkan variabel) apa pun. Dan kata kunci dapat dilihat hanya sebagai fungsi atau operator dengan nama yang dipesan (yang berguna dalam merancang tata bahasa).
Semua keputusan ini pada akhirnya datang ke bagaimana Anda ingin notasi untuk membaca dan bahwa seperti yang Anda katakan adalah subjektif, meskipun orang dapat membuat beberapa rasionalisasi yang jelas misalnya menggunakan operator infiks biasa untuk matematika karena semua orang tahu mereka
Terakhir Dijkstra menulis pembenaran yang menarik tentang notasi matematika yang ia gunakan, yang mencakup diskusi yang baik tentang pertukaran trade off dari notasi infiks vs awalan
sumber
Bagi saya, operator berhenti menjadi berguna ketika Anda tidak dapat lagi membaca garis kode dengan keras atau di kepala Anda, dan membuatnya masuk akal.
Misalnya,
declare x = 5
dibaca sebagai"declare x equals 5"
ataulet x = 5
dapat dibaca sebagai"let x equal 5"
, yang sangat dapat dimengerti ketika membaca dengan keras, namun membaca@x := 5
dibaca sebagai"at x colon equals 5"
(atau"at x is defined to be 5"
jika Anda seorang ahli matematika), yang tidak masuk akal sama sekali.Jadi menurut saya, gunakan operator jika kodenya dapat dibacakan dengan keras dan dipahami oleh orang yang cukup cerdas yang tidak terbiasa dengan bahasa tersebut, tetapi gunakan nama fungsi jika tidak.
sumber
@x := 5
sulit untuk mencari tahu - saya masih membacanya dengan keras untuk diri saya sendiriset x to be equal to 5
.:=
memiliki penggunaan yang lebih luas dalam notasi matematika di luar bahasa pemrograman. Juga, pernyataan sepertix = x + 1
menjadi sedikit tidak masuk akal.:=
sebagai tugas. Beberapa bahasa benar-benar menggunakannya. Smalltalk, saya pikir, mungkin yang paling terkenal. Apakah penugasan dan kesetaraan harus menjadi operator yang terpisah adalah suatu kaleng cacing yang sama sekali berbeda, satu kemungkinan sudah tercakup oleh pertanyaan lain.:=
itu digunakan dalam matematika. Satu definisi yang saya temukan untuk itu adalah "didefinisikan sebagai" jadi@x := 5
akan diterjemahkan ke dalam bahasa Inggris"at x is defined to be 5"
, yang bagi saya masih tidak masuk akal seperti seharusnya.Seorang operator jelas dan berguna ketika akrab. Dan itu mungkin berarti bahwa operator kelebihan muatan harus dilakukan hanya ketika operator yang dipilih cukup dekat (seperti dalam bentuk, diutamakan dan asosiasi) sebagai praktik yang sudah mapan.
Namun menggali sedikit lebih jauh, ada dua aspek.
Sintaks (infiks untuk operator sebagai lawan awalan untuk sintaks panggilan fungsi) dan penamaan.
Untuk sintaksis, ada kasus lain di mana infiks cukup jelas dari pada awalan sehingga dapat membuat upaya menjadi akrab: ketika panggilan dirantai dan bersarang.
Bandingkan
a * b + c * d + e * f
dengan+(+(*(a, b), *(c, d)), *(e, f))
atau+ + * a b * c d * e f
(keduanya parsable dalam kondisi yang sama dengan versi infix). Fakta bahwa+
memisahkan istilah daripada mendahului salah satunya dengan jauh membuatnya lebih mudah dibaca di mata saya (tetapi Anda harus mengingat aturan prioritas yang tidak diperlukan untuk sintaks awalan). Jika Anda perlu menambahkan banyak hal dengan cara ini, manfaat jangka panjangnya sepadan dengan biaya belajar. Dan Anda tetap mendapatkan keuntungan ini bahkan jika Anda memberi nama operator Anda dengan huruf daripada menggunakan simbol.Mengenai penamaan operator, saya melihat beberapa keuntungan dalam menggunakan sesuatu yang lain daripada simbol yang ditetapkan atau nama yang jelas. Ya mereka mungkin lebih pendek, tetapi mereka benar-benar samar dan akan segera dilupakan jika Anda tidak memiliki alasan yang baik untuk sudah mengenal mereka.
Aspek ketiga jika Anda mengambil POV desain bahasa, adalah jika set operator harus terbuka atau tertutup - dapatkah Anda menambahkan operator atau tidak -, dan apakah prioritas dan asosiatif harus ditentukan oleh pengguna atau tidak. Langkah pertama saya adalah berhati-hati dan tidak memberikan prioritas dan asosiatif yang dapat ditentukan pengguna, sementara saya akan lebih terbuka untuk memiliki set terbuka (itu akan meningkatkan dorongan untuk menggunakan overloading operator, tetapi akan mengurangi yang menggunakan yang buruk hanya untuk mendapatkan manfaat dari sintaks infix yang berguna).
sumber
Operator-sebagai-simbol berguna ketika secara intuitif masuk akal.
+
dan-
jelas penambahan dan pengurangan, misalnya, itulah sebabnya hampir setiap bahasa pernah menggunakan mereka sebagai operator mereka. Sama dengan perbandingan (<
dan>
diajarkan di sekolah dasar, dan<=
dan>=
merupakan ekstensi intuitif dari perbandingan dasar ketika Anda memahami bahwa tidak ada tombol perbandingan bergaris bawah pada keyboard standar.)*
dan/
kurang segera jelas, tetapi mereka digunakan secara universal dan posisi mereka pada tombol angka tepat di sebelah+
dan-
tombol membantu memberikan konteks. C's<<
dan>>
berada dalam kategori yang sama: ketika Anda memahami apa itu shift kiri dan kanan, itu tidak terlalu sulit untuk memahami mnemonik di belakang panah.Kemudian Anda datang ke beberapa yang benar-benar aneh, hal-hal yang dapat mengubah kode C menjadi sup operator yang tidak dapat dibaca. (Memilih C di sini karena ini adalah contoh yang sangat berat bagi operator yang sintaksisnya sudah cukup dikenal oleh semua orang, melalui bekerja dengan C atau dengan bahasa turunan.) Misalnya, kemudian
%
operator. Semua orang tahu apa itu: itu tanda persen ... kan? Kecuali di C, itu tidak ada hubungannya dengan pembagian dengan 100; itu adalah operator modulus. Itu tidak masuk akal secara mnemonik, tetapi itu dia!Lebih buruk lagi adalah operator boolean.
&
sebagai dan masuk akal, kecuali bahwa ada dua&
operator yang berbeda yang melakukan dua hal yang berbeda, dan keduanya secara sintaksis berlaku dalam kasus di mana salah satu dari mereka valid, meskipun hanya satu dari mereka yang benar-benar masuk akal dalam setiap kasus yang diberikan. Itu hanya resep untuk kebingungan! Operator atau , xor dan bukan bahkan lebih buruk, karena mereka tidak menggunakan simbol yang berguna secara mnemonik, dan juga tidak konsisten. (Tidak ada ganda xor operator, dan logis dan bitwise tidak menggunakan dua simbol yang berbeda, bukan satu simbol dan versi dua kali lipat-up.)Dan hanya untuk membuatnya lebih buruk,
&
dan*
operator akan digunakan kembali untuk hal-hal yang sama sekali berbeda, yang membuat bahasa lebih sulit bagi orang dan kompiler untuk diurai. (ApaA * B
maksudnya? Itu sepenuhnya tergantung pada konteksnya: apakahA
suatu tipe atau variabel?)Harus diakui, saya tidak pernah berbicara dengan Dennis Ritchie dan bertanya kepadanya tentang keputusan desain yang dibuatnya dalam bahasa tersebut, tetapi begitu banyak yang terasa seperti filosofi di balik operator adalah "simbol demi simbol."
Bandingkan ini dengan Pascal, yang memiliki operator yang sama dengan C, tetapi filosofi yang berbeda dalam mewakili mereka: operator harus intuitif dan mudah dibaca. Operator aritmatika adalah sama. Operator modulus adalah kata
mod
, karena tidak ada simbol pada keyboard yang jelas berarti "modulus". Operator logis adalahand
,or
,xor
dannot
, dan hanya ada satu dari masing-masing; kompiler tahu apakah Anda memerlukan versi boolean atau bitwise berdasarkan apakah Anda beroperasi pada boolean atau angka, menghilangkan seluruh kelas kesalahan. Ini membuat kode Pascal jauh lebih mudah dipahami daripada kode C, terutama dalam editor modern dengan penyorotan sintaks sehingga operator dan kata kunci secara visual berbeda dari pengidentifikasi.sumber
and
danor
sepanjang waktu. Ketika ia mengembangkan Pascal, ia melakukannya pada mainframe Data Kontrol, yang menggunakan karakter 6-bit. Itu memaksa keputusan untuk menggunakan kata-kata untuk banyak hal, karena alasan sederhana bahwa rangkaian karakter tidak memiliki ruang yang hampir sama untuk simbol dan seperti sesuatu seperti ASCII. Saya telah menggunakan C dan Pascal, dan menemukan C secara substansial lebih mudah dibaca. Anda mungkin lebih suka Pascal, tapi itu masalah selera, bukan fakta.|
(dan, dengan ekstensi,||
) untuk atau masuk akal. Anda juga melihatnya setiap saat untuk berganti-ganti dalam konteks lain, seperti tata bahasa, dan sepertinya membagi dua opsi.Saya pikir operator jauh lebih mudah dibaca ketika fungsinya sangat mirip dengan tujuan matematika mereka. Misalnya, operator standar seperti +, -, dll. Lebih mudah dibaca daripada Tambah atau Kurangi saat melakukan penambahan dan pengurangan. Perilaku operator harus didefinisikan dengan jelas. Saya bisa mentolerir kelebihan arti + untuk daftar gabungan, misalnya. Idealnya operasi tidak akan memiliki efek samping, mengembalikan nilai alih-alih bermutasi.
Saya telah berjuang dengan operator pintas untuk fungsi seperti lipatan. Jelas lebih banyak pengalaman dengan mereka akan memudahkan ini, tetapi saya menemukan
foldRight
lebih mudah dibaca daripada/:
.sumber
fold
cukup sering sehingga operator menghemat banyak waktu. Itu mungkin juga mengapa LISPy (+ 1 2 3) tampak aneh tetapi (tambah 1 2 3) kurang begitu. Kami cenderung menganggap operator sebagai biner ketat.>>.
Operator gaya Parsec mungkin konyol, tetapi setidaknya hal utama yang Anda lakukan di Parsec adalah menggabungkan parser, jadi operator untuknya memang banyak digunakan.Masalah dengan operator adalah bahwa hanya ada sedikit dari mereka dibandingkan dengan jumlah nama metode sensical (!) Yang dapat digunakan sebagai gantinya. Efek sampingnya adalah bahwa operator yang dapat ditentukan pengguna cenderung menimbulkan banyak kelebihan.
Tentu saja, kalimat
C = A * x + b * c
itu lebih mudah ditulis dan dibaca daripadaC = A.multiplyVector(x).addVector(b.multiplyScalar(c))
.Atau, yah, tentu lebih mudah untuk menulis, jika Anda memiliki semua versi yang berlebihan dari semua operator di kepala Anda. Dan Anda dapat membacanya setelah itu, sambil memperbaiki bug kedua hingga terakhir.
Sekarang, untuk sebagian besar kode yang akan berjalan di sana, tidak apa-apa. "Proyek ini lulus semua tes, dan ini berjalan" - untuk banyak perangkat lunak, itu saja yang dapat kita inginkan.
Tetapi segala sesuatunya berjalan berbeda ketika Anda melakukan perangkat lunak yang masuk ke area kritis. Keamanan penting. Keamanan. Perangkat lunak yang membuat pesawat tetap terbang, atau yang membuat fasilitas nuklir tetap berjalan. Atau perangkat lunak yang mengenkripsi email Anda yang sangat rahasia.
Untuk pakar keamanan yang berspesialisasi dalam kode audit, ini bisa menjadi mimpi buruk. Gabungan dari banyak operator yang ditentukan pengguna dan overloading operator dapat membuat mereka dalam situasi yang tidak menyenangkan sehingga mereka kesulitan menemukan kode apa yang akan dijalankan pada akhirnya.
Jadi, seperti yang dinyatakan dalam pertanyaan awal, ini adalah subjek yang sangat subyektif. Dan sementara banyak saran tentang bagaimana operator harus digunakan mungkin terdengar sangat sensasional, kombinasi hanya beberapa dari mereka mungkin membuat banyak masalah dalam jangka panjang.
sumber
Saya kira contoh paling ekstrem adalah APL, program berikut adalah "game of life":
Dan jika Anda dapat mengetahui apa artinya semua tanpa menghabiskan beberapa hari dengan manual referensi maka semoga sukses untuk Anda!
Masalahnya adalah Anda memiliki seperangkat simbol yang secara intuitif dipahami hampir semua orang:
+,-,*,/,%,=,==,&
dan sisanya yang memerlukan penjelasan sebelum dapat dipahami, dan, umumnya khusus untuk bahasa tertentu. Misalnya tidak ada simbol yang jelas untuk menentukan anggota array yang Anda inginkan, [], () dan bahkan "." telah digunakan, tetapi sama-sama tidak ada kata kunci jelas yang dapat Anda gunakan dengan mudah, jadi ada kasus yang harus dibuat untuk penggunaan operator secara bijaksana. Tapi tidak terlalu banyak.
sumber