Jika saya ingin membandingkan dua angka (atau entitas yang tertata dengan baik), saya akan melakukannya dengan x < y
. Jika saya ingin membandingkan tiga dari mereka, siswa aljabar sekolah menengah akan menyarankan mencoba x < y < z
. Programmer dalam diri saya kemudian akan menjawab dengan "tidak, itu tidak valid, Anda harus melakukan x < y && y < z
".
Sebagian besar bahasa yang saya temui tampaknya tidak mendukung sintaks ini, yang aneh mengingat betapa umum itu dalam matematika. Python adalah pengecualian penting. JavaScript terlihat seperti pengecualian, tetapi sebenarnya hanya produk sampingan yang kurang menguntungkan dari operator yang didahulukan dan konversi tersirat; di node.js, 1 < 3 < 2
dievaluasi menjadi true
, karena itu benar-benar (1 < 3) < 2 === true < 2 === 1 < 2
.
Jadi, pertanyaan saya adalah ini: Mengapa x < y < z
tidak tersedia secara umum dalam bahasa pemrograman, dengan semantik yang diharapkan?
static bool IsInRange<T>(this T candidate, T lower, T upper) where T : IComparable<T>
jika itu benar-benar mengganggu Anda untuk melihatnya&&
)Jawaban:
Ini adalah operator biner, yang ketika dirantai, secara normal dan alami menghasilkan pohon sintaksis abstrak seperti:
Ketika dievaluasi (yang Anda lakukan dari daun ke atas), ini menghasilkan hasil boolean dari
x < y
, maka Anda mendapatkan kesalahan ketik yang coba dilakukanboolean < z
. Agarx < y < z
berfungsi seperti yang Anda diskusikan, Anda harus membuat case khusus di kompiler untuk menghasilkan pohon sintaksis seperti:Bukannya tidak mungkin melakukan ini. Jelas itu, tetapi menambahkan beberapa kompleksitas ke parser untuk kasus yang tidak terlalu sering muncul. Pada dasarnya Anda membuat simbol yang terkadang bertindak seperti operator biner dan kadang-kadang bertindak secara efektif seperti operator ternary, dengan semua implikasi penanganan kesalahan dan yang memerlukannya. Itu menambah banyak ruang untuk kesalahan yang tidak diinginkan oleh perancang bahasa jika memungkinkan.
sumber
x<y<z
artinya, atau yang lebih pentingx<y<=z
,. Jawaban ini diartikanx<y<z
sebagai operator trinary. Persis bagaimana ekspresi matematika yang terdefinisi dengan baik ini seharusnya tidak diinterpretasikan.x<y<z
bukan singkatan untuk(x<y)&&(y<z)
. Perbandingan individu masih bersifat biner.Mengapa
x < y < z
tidak tersedia secara umum dalam bahasa pemrograman?Dalam jawaban ini saya menyimpulkan itu
pengantar
Saya bisa berbicara dari perspektif Pythonist tentang pertanyaan ini. Saya adalah pengguna bahasa dengan fitur ini dan saya suka mempelajari detail implementasi bahasa. Di luar ini, saya agak akrab dengan proses perubahan bahasa seperti C dan C ++ (standar ISO diatur oleh komite dan versi menurut tahun.) Dan saya telah menyaksikan Ruby dan Python mengimplementasikan perubahan yang melanggar.
Dokumentasi dan implementasi Python
Dari dokumen / tata bahasa, kami melihat bahwa kami dapat memadukan sejumlah ekspresi dengan operator pembanding:
dan dokumentasi selanjutnya menyatakan:
Kesetaraan logis
Begitu
secara logis setara dalam hal evaluasi
x
,y
danz
, dengan pengecualian yangy
dievaluasi dua kali:Sekali lagi, perbedaannya adalah bahwa y hanya dievaluasi satu kali dengan
(x < y <= z)
.(Catatan, tanda kurung sama sekali tidak perlu dan mubazir, tetapi saya menggunakannya untuk kepentingan yang berasal dari bahasa lain, dan kode di atas adalah Python yang cukup legal.)
Memeriksa Pohon Sintaks Abstrak yang diuraikan
Kita dapat memeriksa bagaimana Python mem-parsing operator perbandingan:
Jadi kita dapat melihat bahwa ini sebenarnya tidak sulit untuk Python atau bahasa lain untuk diuraikan.
Dan bertentangan dengan jawaban yang diterima saat ini, operasi ternary adalah operasi perbandingan generik, yang mengambil ekspresi pertama, iterable dari perbandingan spesifik dan iterable dari node ekspresi untuk mengevaluasi yang diperlukan. Sederhana.
Kesimpulan tentang Python
Saya pribadi menemukan bahwa semantik jangkauannya cukup elegan, dan sebagian besar profesional Python yang saya kenal akan mendorong penggunaan fitur ini, alih-alih menganggapnya merusak - semantiknya dinyatakan dengan jelas dalam dokumentasi terkenal (seperti disebutkan di atas).
Perhatikan bahwa kode lebih banyak dibaca daripada yang tertulis. Perubahan yang meningkatkan keterbacaan kode harus dianut, tidak diabaikan dengan meningkatkan momok umum Ketakutan, Ketidakpastian, dan Keraguan .
Jadi mengapa x <y <z tidak umum tersedia dalam bahasa pemrograman?
Saya pikir ada pertemuan alasan yang berpusat di sekitar kepentingan relatif fitur dan momentum relatif / kelembaman perubahan yang diizinkan oleh para gubernur bahasa.
Pertanyaan serupa dapat ditanyakan tentang fitur bahasa lain yang lebih penting
Mengapa pewarisan berganda tidak tersedia di Java atau C #? Tidak ada jawaban yang baik untuk pertanyaan ini . Mungkin para pengembang terlalu malas, sebagaimana ditegaskan Bob Martin, dan alasan yang diberikan hanyalah alasan. Dan multiple inheritance adalah topik yang cukup besar dalam ilmu komputer. Ini tentu saja lebih penting daripada perangkaian operator.
Ada solusi sederhana
Chaining operator pembanding adalah elegan, tetapi sama sekali tidak sepenting warisan ganda. Dan seperti halnya Java dan C # memiliki antarmuka sebagai solusi, demikian juga setiap bahasa untuk beberapa perbandingan - Anda cukup mengaitkan perbandingan dengan boolean "dan" s, yang bekerja dengan cukup mudah.
Sebagian besar bahasa diatur oleh komite
Sebagian besar bahasa berevolusi oleh komite (daripada memiliki Diktator Kebajikan Sejati yang masuk akal seperti yang dimiliki Python). Dan saya berspekulasi bahwa masalah ini hanya belum melihat cukup dukungan untuk keluar dari komite masing-masing.
Bisakah bahasa yang tidak menawarkan fitur ini berubah?
Jika suatu bahasa memungkinkan
x < y < z
tanpa semantik matematika yang diharapkan, ini akan menjadi perubahan besar. Jika tidak mengizinkannya di tempat pertama, itu akan hampir sepele untuk ditambahkan.Memecah perubahan
Mengenai bahasa dengan perubahan yang rusak: kami memperbarui bahasa dengan mengubah perubahan perilaku - tetapi pengguna cenderung tidak menyukai ini, terutama pengguna fitur yang mungkin rusak. Jika seorang pengguna mengandalkan perilaku sebelumnya
x < y < z
, mereka kemungkinan besar akan protes keras. Dan karena sebagian besar bahasa diatur oleh komite, saya ragu kita akan mendapatkan banyak kemauan politik untuk mendukung perubahan semacam itu.sumber
x < y < z
untuk(x < y) && (y < z)
. Memilih nits, model mental untuk perbandingan dirantai adalah matematika umum. Perbandingan klasik bukanlah matematika secara umum, tetapi logika Boolean.x < y
menghasilkan jawaban biner{0}
.y < z
menghasilkan jawaban biner{1}
.{0} && {1}
menghasilkan jawaban deskriptif. Logikanya tersusun, tidak dirantai secara naif.x<y<z
. Suatu bahasa pernah memiliki kesempatan untuk mendapatkan sesuatu seperti ini dengan benar, dan satu peluang itu adalah pada saat permulaan bahasa tersebut.I have watched both Ruby and Python implement breaking changes.
Bagi mereka yang ingin tahu, berikut adalah perubahan melanggar di C # 5.0 yang melibatkan variabel lingkaran dan penutupan: blogs.msdn.microsoft.com/ericlippert/2009/11/12/...Bahasa komputer mencoba untuk mendefinisikan unit terkecil yang mungkin dan membiarkan Anda menggabungkannya. Unit terkecil yang mungkin adalah sesuatu seperti "x <y" yang memberikan hasil boolean.
Anda dapat meminta operator ternary. Contohnya adalah x <y <z. Sekarang kombinasi operator apa yang kami izinkan? Jelas x> y> z atau x> = y> = z atau x> y> = z atau mungkin x == y == z harus diizinkan. Bagaimana dengan x <y> z? x! = y! = z? Apa arti yang terakhir, x! = Y dan y! = Z atau ketiganya berbeda?
Sekarang promosi argumen: Di C atau C ++, argumen akan dipromosikan ke tipe umum. Jadi, apa artinya x <y <z dari x adalah ganda tetapi y dan z adalah int panjang? Ketiganya dipromosikan menjadi dua kali lipat? Atau y diambil dua kali dan selama di waktu yang lain? Apa yang terjadi jika dalam C ++ satu atau kedua operator kelebihan beban?
Dan terakhir, apakah Anda mengizinkan sejumlah operan? Seperti a <b> c <d> e <f> g?
Nah, itu semua menjadi sangat rumit. Sekarang apa yang saya tidak keberatan adalah x <y <z menghasilkan kesalahan sintaksis. Karena kegunaannya kecil dibandingkan dengan kerusakan yang dilakukan untuk pemula yang tidak tahu apa yang sebenarnya x <y <z lakukan.
sumber
x + y + z
, dengan satu-satunya perbedaan yang tidak menyiratkan perbedaan semantik. Jadi hanya saja tidak ada bahasa terkenal yang pernah peduli untuk melakukannya.x < y < z
setara dengan((x < y) and (y < z))
tetapiy
hanya dievaluasi sekali ) yang saya bayangkan bahasa yang dikompilasi mengoptimalkan jalan mereka. "Karena kegunaannya kecil dibandingkan dengan kerusakan yang dilakukan untuk pemula yang tidak tahu apa yang sebenarnya <<y <z lakukan." Saya pikir ini sangat berguna. Mungkin akan -1 untuk itu ...a < b > c < d > e < f > g
, dengan makna "jelas"(a < b) and (b > c) and (c < d) and (d > e) and (e < f) and (f > g)
. Hanya karena Anda dapat menulis bukan berarti Anda harus menulis. Menghilangkan keburukan semacam itu adalah bidang tinjauan kode. Di sisi lain, menulis0 < x < 8
dengan python memiliki arti yang jelas (tanpa tanda kutip) yang berarti bahwa x terletak antara 0 dan 8, eksklusif.Dalam banyak bahasa pemrograman,
x < y
adalah ekspresi biner yang menerima dua operan dan mengevaluasi ke hasil boolean tunggal. Oleh karena itu, jika perangkaian banyak ekspresi,true < z
danfalse < z
tidak masuk akal, dan jika ekspresi tersebut berhasil dievaluasi, mereka cenderung menghasilkan hasil yang salah.Jauh lebih mudah untuk dianggap
x < y
sebagai pemanggilan fungsi yang mengambil dua parameter dan menghasilkan hasil boolean tunggal. Bahkan, itulah berapa banyak bahasa yang mengimplementasikannya di bawah tenda. Ini komposable, mudah dikompilasi, dan hanya berfungsi.The
x < y < z
Skenario jauh lebih rumit. Sekarang kompiler harus membuat tiga fungsi:x < y
,,y < z
dan hasil dari kedua nilai tersebut digabungkan bersama-sama, semua dalam konteks tata bahasa yang bisa dibilang ambigu .Mengapa mereka melakukannya dengan cara lain? Karena itu tata bahasa yang tidak ambigu, jauh lebih mudah diimplementasikan, dan jauh lebih mudah untuk diperbaiki.
sumber
e1 op1 e2 op2 e3 op3 ...
setara dengane1 op e2 and e2 op2 e3 and ...
kecuali bahwa setiap ekspresi hanya dievaluasi satu kali. (BTW aturan sederhana ini memiliki efek samping yang membingungkan bahwa pernyataan sepertia == b is True
tidak lagi memiliki efek yang diinginkan.)re:answer
Di sinilah pikiran saya segera pergi juga untuk komentar saya pada pertanyaan utama. Saya tidak mempertimbangkan dukungan untukx < y < z
menambahkan nilai spesifik ke semantik bahasa.(x < y) && (y < z)
lebih didukung secara luas, lebih eksplisit, lebih ekspresif, lebih mudah dicerna ke dalam konstituennya, lebih mudah dikomposisikan, lebih logis, lebih mudah di refactored.Sebagian besar bahasa arus utama (setidaknya sebagian) berorientasi objek. Pada dasarnya, prinsip yang mendasari OO adalah bahwa objek mengirim pesan ke objek lain (atau diri mereka sendiri), dan penerima pesan itu memiliki kontrol penuh atas bagaimana menanggapi pesan itu.
Sekarang, mari kita lihat bagaimana kita mengimplementasikan sesuatu seperti
Kami dapat mengevaluasinya dengan ketat dari kiri ke kanan (asosiasi kiri):
Tetapi sekarang kita memanggil
__lt__
hasila.__lt__(b)
, yaitu aBoolean
. Itu tidak masuk akal.Mari kita coba asosiatif yang benar:
Nah, itu juga tidak masuk akal. Sekarang, sudah
a < (something that's a Boolean)
.Oke, bagaimana kalau memperlakukannya sebagai gula sintaksis. Mari kita membuat rantai
<
perbandingan n mengirim pesan n-1-ary. Ini bisa berarti, kami mengirim pesan__lt__
kea
, lewat,b
danc
sebagai argumen:Oke, itu berhasil, tapi ada asimetri yang aneh di sini:
a
harus memutuskan apakah itu kurangb
. Tetapib
tidak bisa memutuskan apakah itu kurang daric
, sebaliknya keputusan itu juga dibuat oleha
.Bagaimana dengan menafsirkannya sebagai pesan n-ary yang dikirim ke
this
?Akhirnya! Ini bisa berhasil. Ini berarti, bagaimanapun, bahwa pemesanan objek tidak lagi menjadi properti dari objek (misalnya apakah
a
kurang darib
itu bukan propertia
atau bukanb
) tetapi sebagai properti dari konteks (yaituthis
).Dari sudut pandang arus utama itu tampak aneh. Namun, misalnya di Haskell, itu normal. Mungkin ada beberapa implementasi berbeda dari
Ord
typeclass, misalnya, dan apakaha
kurang atau tidakb
, tergantung pada instance typeclass mana yang berada dalam ruang lingkup.Tapi sebenarnya, tidak bahwa aneh sekali! Java (
Comparator
) dan .NET (IComparer
) memiliki antarmuka yang memungkinkan Anda untuk menyuntikkan relasi pemesanan Anda sendiri ke dalam misalnya algoritma penyortiran. Dengan demikian, mereka sepenuhnya mengakui bahwa pemesanan bukanlah sesuatu yang ditetapkan untuk suatu tipe melainkan tergantung pada konteks.Sejauh yang saya tahu, saat ini tidak ada bahasa yang melakukan terjemahan seperti itu. Namun, ada satu yang lebih diutamakan: Ioke dan Seph memiliki apa yang oleh perancang mereka sebut "operator trinary" - operator yang secara biner sintaksis , tetapi terner semantik . Khususnya,
adalah tidak ditafsirkan sebagai mengirimkan pesan
=
kea
lewatb
sebagai argumen, melainkan sebagai mengirimkan pesan=
ke "tanah saat ini" (konsep serupa tetapi tidak identik denganthis
) lewata
danb
sebagai argumen. Jadi,a = b
diartikan sebagaidan tidak
Ini dengan mudah dapat digeneralisasi ke operator n-ary.
Perhatikan bahwa ini sangat aneh untuk bahasa OO. Dalam OO, kami selalu memiliki satu objek tunggal yang pada akhirnya bertanggung jawab untuk menafsirkan pengiriman pesan, dan seperti yang telah kita lihat, tidak segera jelas untuk sesuatu seperti
a < b < c
objek mana yang seharusnya.Ini tidak berlaku untuk bahasa prosedural atau fungsional. Misalnya, dalam Skema , Common Lisp , dan Clojure ,
<
fungsinya adalah n-ary, dan dapat dipanggil dengan sejumlah argumen arbitrer.Secara khusus,
<
tidak tidak berarti "kurang dari", bukan fungsi-fungsi ini ditafsirkan sedikit berbeda:sumber
Itu hanya karena perancang bahasa tidak memikirkannya atau tidak menganggap itu ide yang bagus. Python melakukannya seperti yang Anda gambarkan dengan tata bahasa LL (1) sederhana (hampir).
sumber
1 < 2 < 3
ke dalam Java atau C # dan Anda tidak memiliki masalah dengan prioritas operator; Anda memiliki masalah dengan jenis yang tidak valid. Masalahnya adalah ini masih akan diuraikan persis seperti yang Anda tulis, tetapi Anda perlu logika kasus khusus di kompiler untuk mengubahnya dari urutan perbandingan individual ke perbandingan berantai.Program C ++ berikut mengkompilasi dengan mengintip dari dentang, bahkan dengan peringatan yang diatur ke tingkat setinggi mungkin (
-Weverything
):Suite compiler gnu di sisi lain dengan baik memperingatkan saya itu
comparisons like 'X<=Y<=Z' do not have their mathematical meaning [-Wparentheses]
.Jawabannya sederhana: Kompatibilitas mundur. Ada sejumlah besar kode di alam bebas yang menggunakan yang setara
1<3<2
dan berharap hasilnya benar.Perancang bahasa hanya memiliki satu kesempatan untuk mendapatkan "hak" ini, dan itulah titik waktu bahasa pertama kali dirancang. Melakukannya "salah" pada awalnya berarti programmer lain akan lebih cepat mengambil keuntungan dari perilaku "salah" itu. Melakukannya dengan "benar" untuk yang kedua kalinya akan merusak basis kode yang ada.
sumber
if x == y is True : ...
, Pendapat saya: Orang-orang yang menulis kode semacam itu layak mengalami penyiksaan yang luar biasa dan luar biasa yang (jika ia hidup sekarang) akan membuat Torquemada sendiri pingsan.