Apakah operator lebih jelas membaca daripada kata kunci atau fungsi? [Tutup]

14

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) xVB: CType(x, int32)F #:x :> int32

Secara teori, bahasa baru dapat memiliki operator untuk sebagian besar fungsi bawaan. Alih-alih defatau decatau varuntuk deklarasi variabel, mengapa tidak ! nameatau @ nameatau yang serupa. Ini tentu saja mempersingkat deklarasi diikuti dengan mengikat: @x := 5bukan declare x = 5atau let x = 5 Kebanyakan kode akan membutuhkan banyak definisi variabel, jadi mengapa tidak?

Kapan operator jelas dan berguna, dan kapan itu mengaburkan?

CodexArcanum
sumber
1
Saya berharap salah satu dari 1.000 pengembang yang pernah mengeluh kepada saya tentang kurangnya kelebihan operator di Jawa akan menjawab pertanyaan ini.
smp7d
1
Saya telah memikirkan APL ketika saya selesai mengetik pertanyaan, tetapi dalam beberapa hal yang menjelaskan poin dan memindahkannya ke wilayah yang agak kurang subyektif. Saya pikir sebagian besar orang bisa setuju bahwa APL kehilangan sesuatu dengan mudah melalui jumlah operatornya yang ekstrem, tetapi jumlah orang yang mengeluh ketika suatu bahasa tidak memiliki operator yang berlebihan pasti berbicara mendukung beberapa fungsi yang cocok untuk bertindak sebagai operator. Antara operator kustom terlarang dan apa pun selain operator, harus ada menyembunyikan beberapa pedoman untuk implementasi dan penggunaan praktis.
CodexArcanum
Seperti yang saya lihat, kurangnya overloading operator tidak dapat diterima karena ini mengistimewakan tipe asli dari tipe yang ditentukan pengguna (perhatikan bahwa Java melakukan ini dengan cara lain juga). Saya jauh lebih ambivalen tentang operator kustom bergaya Haskell, yang sepertinya merupakan undangan terbuka untuk masalah ...
badai
2
@comingstorm: Saya benar-benar berpikir cara Haskell lebih baik. Ketika Anda memiliki satu set operator yang terbatas yang dapat Anda overload dengan cara yang berbeda, Anda sering dipaksa untuk menggunakan kembali operator dalam konteks yang berbeda (misalnya +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.
Tikhon Jelvis

Jawaban:

16

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

jk.
sumber
4
Saya ingin memberi Anda +1 kedua untuk tautan ke makalah Dijkstra.
Pemrogram
Tautan hebat, Anda harus menerbitkan akun PayPal! ;)
Adriano Repetti
8

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 = 5dibaca sebagai "declare x equals 5"atau let x = 5dapat dibaca sebagai "let x equal 5", yang sangat dapat dimengerti ketika membaca dengan keras, namun membaca @x := 5dibaca 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.

Rachel
sumber
5
Saya pikir tidak @x := 5sulit untuk mencari tahu - saya masih membacanya dengan keras untuk diri saya sendiri set x to be equal to 5.
FrustratedWithFormsDesigner
3
@Rachel, dalam hal ini, :=memiliki penggunaan yang lebih luas dalam notasi matematika di luar bahasa pemrograman. Juga, pernyataan seperti x = x + 1menjadi sedikit tidak masuk akal.
ccoakley
3
Ironisnya, saya lupa bahwa beberapa orang tidak akan mengenali :=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.
CodexArcanum
1
@ccoakley Terima kasih, saya tidak menyadari bahwa :=itu digunakan dalam matematika. Satu definisi yang saya temukan untuk itu adalah "didefinisikan sebagai" jadi @x := 5akan diterjemahkan ke dalam bahasa Inggris "at x is defined to be 5", yang bagi saya masih tidak masuk akal seperti seharusnya.
Rachel
1
Tentu saja Pascal digunakan: = sebagai tugas, karena kurangnya panah kiri di ASCII.
Vatine
4

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 * fdengan +(+(*(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).

Pemrogram
sumber
Jika pengguna dapat menambahkan operator, mengapa tidak membiarkan mereka mengatur prioritas dan asosiasi operator yang telah mereka tambahkan?
Tikhon Jelvis
@TikhonJelvis, sebagian besar konservatif, tetapi ada beberapa aspek yang perlu dipertimbangkan jika Anda ingin dapat menggunakannya untuk hal lain selain contoh. Misalnya, Anda ingin mengikat prioritas dan asosiasi ke operator, bukan anggota yang ditentukan dari kelebihan beban (Anda memilih anggota setelah parsing dilakukan, pilihan tidak dapat mempengaruhi parsing). Jadi untuk mengintegrasikan perpustakaan menggunakan operator yang sama, mereka harus menyepakati prioritas dan asosiatifitasnya. Sebelum menambahkan kemungkinan, saya akan mencoba mencari tahu mengapa begitu sedikit bahasa mengikuti Algol 68 (tidak ada AFAIK) dan diizinkan untuk mendefinisikannya.
Pemrogram
Nah, Haskell memungkinkan Anda mendefinisikan operator yang sewenang-wenang dan menetapkan prioritas dan asosiatifitas mereka. Perbedaannya adalah bahwa Anda tidak dapat membebani operator per se - mereka berperilaku seperti fungsi normal. Ini berarti Anda tidak dapat memiliki pustaka yang berbeda yang mencoba menggunakan operator yang sama untuk hal yang berbeda. Karena Anda dapat mendefinisikan operator Anda sendiri, ada jauh lebih sedikit alasan untuk menggunakan kembali yang sama untuk hal-hal yang berbeda.
Tikhon Jelvis
1

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. (Apa A * Bmaksudnya? Itu sepenuhnya tergantung pada konteksnya: apakah Asuatu 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 adalah and, or, xordan not, 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.

Mason Wheeler
sumber
4
Pascal sama sekali tidak mewakili filosofi yang berbeda. Jika Anda membaca makalah Wirth, ia menggunakan simbol untuk hal-hal seperti anddan orsepanjang 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.
Jerry Coffin
Untuk menambahkan komentar @JerryCoffin tentang Wirth, bahasa-bahasa berikutnya (Modula, Oberon) menggunakan lebih banyak simbol.
Pemrogram
@AProgrammer: Dan mereka tidak pernah pergi ke mana pun. ;)
Mason Wheeler
Saya pikir |(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.
Tikhon Jelvis
1
Keuntungan kata kunci berbasis surat adalah bahwa ruang mereka jauh lebih besar daripada simbol. Misalnya, bahasa gaya Pascal dapat mencakup operator untuk "modulus" dan "sisanya", dan untuk pembagian bilangan bulat versus mengambang (yang memiliki arti berbeda di luar jenis operan mereka).
supercat
1

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 foldRightlebih mudah dibaca daripada /:.

Matt H
sumber
4
Mungkin frekuensi penggunaan juga masuk ke dalamnya. Saya tidak akan berpikir Anda foldcukup 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.
CodexArcanum
1

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 * citu lebih mudah ditulis dan dibaca daripada C = 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.

bodoh
sumber
0

Saya kira contoh paling ekstrem adalah APL, program berikut adalah "game of life":

life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}

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.

James Anderson
sumber