Operator ternary dianggap berbahaya? [Tutup]


79

Misalnya, apakah Anda lebih suka one-liner ini

int median(int a, int b, int c) {
    return (a<b) ? (b<c) ? b : (a<c) ? c : a : (a<c) ? a : (b<c) ? c : b;
}

atau solusi if / else yang melibatkan beberapa pernyataan pengembalian?

Kapan ?:tepat, dan kapan tidak? Haruskah itu diajarkan atau disembunyikan dari pemula?


221
Penggunaan khusus ini adalah :)
karmajunkie

6
Siapa yang mengkodekan itu, dan seperti apa versi median mereka untuk empat angka? Atau lima?
Mason Wheeler

3
Nama yang lebih tepat adalah 'operator kondisional'. Itu hanya kebetulan menjadi operator ternary yang paling umum digunakan.
Alan Pearce

1
Ini ditanyakan lebih dari dua tahun yang lalu di stackoverflow. Apakah kita akan menanyakan kembali semuanya di sini sekarang? stackoverflow.com/questions/160218/to-ternary-or-not-to-ternary
webbiedave

3
Saya terkejut mengapa pertanyaan seperti itu terus muncul. Jawabannya selalu "apa pun yang berhasil dan dapat dibaca." - yang terakhir sama pentingnya.
Apoorv Khurasia

Jawaban:


234

Apakah operator ternary itu jahat?

Tidak, itu adalah berkah.

Kapan itu tepat?

Ketika itu sesuatu yang sangat sederhana, Anda tidak ingin membuang banyak baris.

dan kapan bukan?

Ketika keterbacaan dan kejelasan kode menderita dan potensi kesalahan melalui peningkatan perhatian yang tidak memadai, misalnya, dengan banyak operator rantai, seperti dalam contoh Anda.


Tes lakmus adalah ketika Anda mulai meragukan kode Anda mudah dibaca dan dipelihara dalam jangka panjang. Maka jangan lakukan itu.


23
+1 untuk Ketika keterbacaan dan kejelasan kode menderita. Dengan banyak operator yang dirantai, seperti dalam contoh Anda. Contohnya membutuhkan waktu lebih lama untuk dipahami daripada yang setara jika / orang lain.
agak

23
+1 bravo untuk penjelasan yang luar biasa! Pengembang tidak cenderung menyadari bahwa beberapa hal adalah panggilan penilaian, mereka ingin semuanya hitam dan putih. Itu membuatku gila. Saya telah menemui banyak orang dengan pendapat "X itu jahat, jangan pernah gunakan itu.". Saya lebih suka "X hebat jika Anda menggunakannya untuk apa yang baik".
Pasang kembali Monica

54
Juga jahat jika digunakan: myVar = (someExpression)? benar salah; Aaaaarrgh!
adamk

20
@adamk: Coba ini untuk kejahatan:myVar = someExpression ? false : true;
Dean Harding

8
Bagaimana dengan (someExpression ? var1 : var2)++:-)
fredoverflow

50

Saya pikir operator ternary yang tidak diuji (yaitu, pernyataan di mana ia digunakan hanya sekali) baik-baik saja, tetapi jika Anda bersarang lebih dari satu, itu menjadi agak sulit dibaca.


3
Ini mungkin dianggap penyederhanaan yang berlebihan, tetapi itu adalah pedoman yang sangat mudah diikuti dan berfungsi dalam banyak kasus.
Alan Pearce

2
Ini sebenarnya adalah aturan dasar saya: Anda tidak boleh membuat sarang, jika tidak ganti dengan / jika ada, akan lebih jelas seperti itu.
Piovezan

Jika Anda akan menggunakannya, dan akan membuat sarang, maka untuk cinta kemanusiaan gunakan tanda kurung dan ruang putih untuk membuatnya dapat dibaca. Kalau-kalau bisa dibuat sama jeleknya. Tahan keinginan untuk menunjukkan seberapa 'pintar' Anda dengan menulis hal-hal yang dapat dibaca oleh penyusun tetapi manusia tidak bisa. Suatu hari Anda akan menjadi manusia yang tidak bisa.
candied_orange

24

Kapan itu tepat?

  • Ketika itu membuat kode Anda lebih ringkas dan mudah dibaca.

dan kapan bukan?

  • Ketika itu membuat kode Anda tidak dapat dibaca.
  • Jika Anda melakukannya hanya untuk menyenangkan alat refactoring seperti ReSharper dan bukan orang yang harus menjaga kode

Jika Anda memiliki logika atau panggilan fungsi di dalam ekspresi ternary, Anda membuatnya mengerikan untuk melihatnya.


Yang ini layak mendapat banyak upvotes!
Piovezan

22

Satu perbedaan yang (saya pikir) tidak ada yang tunjukkan adalah jika-selain tidak bisa mengembalikan nilai, sedangkan operator ternary bisa.

Berasal dari F #, saya terkadang suka menggunakan operator ternary untuk meniru pencocokan pola.

match val with
| A -> 1
| B -> 3
| _ -> 0

vs.

return val == A ? 1 : 
       val == B ? 3 : 
       0;

Itu keren sekali. Tidak pernah memikirkan itu.
Rei Miyasaka

+1 @Benjol: Saya akan menunjukkan hal yang sama (bahwa dalam F #, semuanya adalah ekspresi, termasuk jika / elif / lain-lain). Saya menggunakan terner seperti pada contoh Anda juga, sejauh ini juga belum ditemukan :). Hal lain yang telah saya lakukan, dalam Javascript, mungkin di atas, adalah: var res = function() {switch(input) {case 1: return "1"; case 2: return "2"; ...}}()untuk meniru switch sebagai ekspresi.
Stephen Swensen

@Stephen, saya akan menggunakan kata-kata expressiondan statementtapi saya selalu khawatir saya akan mendapatkannya dengan cara yang salah dan mempermalukan diri sendiri :)
Benjol

@Benjol: Saya tahu maksud Anda!
Stephen Swensen

6
Juga berguna dalam C dan C ++ untuk menginisialisasi constvariabel yang tidak dapat diubah nanti.
David Thornley

13

Contoh (IMHO) dari penggunaan yang valid:

printf("Success in %d %s\n", nr_of_tries, (nr_of_tries == 1 ? "try" : "tries"));

Ini menghasilkan kode yang lebih mudah dibaca daripada memiliki 2 pernyataan cetak yang berbeda. Contoh bersarang tergantung: (dapat dimengerti? Ya: tidak)


11
Hanya perlu diingat bahwa jika Anda melakukan ini, Anda membuatnya menjadi neraka bagi siapa pun yang harus melokalisasi aplikasi Anda. Tentu saja, jika itu bukan masalah, silakan saja.
Anon.

1
Itulah aturan saya: 1 tingkat sarang (dalam beberapa keadaan).
Oliver Weiler

7

Sama sekali tidak jahat. Sebenarnya, itu murni , dan jika-maka-tidak.

Dalam bahasa fungsional seperti Haskell, F #, ML dll., Pernyataan if-then-else yang dianggap jahat.

Alasan untuk ini adalah bahwa "tindakan" apa pun seperti pernyataan imperatif if-then-else mengharuskan Anda untuk memisahkan deklarasi variabel dari definisinya, dan memperkenalkan status ke fungsi Anda.

Misalnya, dalam kode berikut:

const var x = n % 3 == 1
    ? Parity.Even
    : Parity.Odd;

vs.

Parity x;
if (n % 3 == 1)
    x = Parity.Even;
else
    x = Parity.Odd;

Yang pertama memiliki dua keunggulan selain lebih pendek:

  1. x adalah konstan, dan karenanya menawarkan lebih sedikit kesempatan untuk memperkenalkan bug, dan berpotensi dapat dioptimalkan dengan cara yang kedua tidak pernah bisa.
  2. Tipe ini dibuat jelas oleh ekspresi, sehingga kompiler dapat dengan mudah menyimpulkan yang xperlu tipe Parity.

Yang membingungkan, dalam bahasa fungsional, operator ternary sering disebut if-then-else. Di Haskell, Anda mungkin berkata x = if n mod 3 == 1 then Odd else Even.


ya, ini poin yang dibuat @Benjol juga. Lihat komentar saya untuk jawabannya untuk cara yang menyenangkan meniru pernyataan beralih sebagai ekspresi dalam Javascript.
Stephen Swensen

7

Ekspresi khusus itu membuat mataku sakit; Saya akan mengecam pengembang apa pun di tim saya yang menggunakannya karena itu tidak dapat dipelihara.

Operator ternary tidak jahat jika digunakan dengan baik. Mereka bahkan tidak harus menjadi satu baris; Yang panjang yang diformat dengan baik bisa sangat jelas dan mudah dimengerti:

return
      ( 'a' == $s ) ? 1
    : ( 'b' == $s ) ? 2
    : ( 'c' == $s ) ? 3
    :                 4;

Saya suka itu lebih baik daripada rantai if / then / else yang setara:

if ( 'a' == $s ) {
    $retval = 1;
}
elsif ( 'b' == $s ) {
    $retval = 2;
}
elsif ( 'c' == $s ) {
    $retval = 3;
}
else {
    $retval = 4;
}

return $retval;

Saya akan memformat ulang mereka menjadi:

if    ( 'a' == $s ) { $retval = 1; }
elsif ( 'b' == $s ) { $retval = 2; }
elsif ( 'c' == $s ) { $retval = 3; }
else                { $retval = 4; }

return $retval;

jika kondisi dan tugas memungkinkan penyelarasan mudah. Tetap saya lebih suka versi terner karena lebih pendek dan tidak memiliki banyak kebisingan di sekitar kondisi dan tugas.


Mengapa saya tidak bisa memasukkan linebreak dalam komentar? Arrgghh!
Christopher Mahan

3

ReSharper di VS.NET terkadang menyarankan untuk mengganti if...elsedengan ?:operator.

Tampaknya ReSharper hanya menyarankan jika kondisi / blok di bawah tingkat kompleksitas tertentu, jika tidak maka akan tetap bertahan if...else.


4
fitur hebat lainnya yang saya sukai dari ReSharper
Anonymous Type

2

Ini dapat diformat ulang agar tampak sama bagusnya dengan kombinasi if / else:

int median(int a, int b, int c)
{
    return
        (a<b)
        ?
            (b<c)
            ? b
            :
                (a<c)
                ? c
                : a
        :
            (a<c)
            ? a
            :
                (b<c)
                ? c
                : b;
}

Tetapi masalahnya adalah bahwa saya tidak begitu yakin apakah saya mendapat lekukan yang benar untuk mewakili apa yang sebenarnya akan terjadi. :-)


3
+1 Saya pikir ini jauh lebih baik daripada if-elsestruktur yang setara . Kuncinya adalah pemformatan.
Orbling

13
Jika saya melihat ini di basis kode, saya serius akan mempertimbangkan mencari pekerjaan baru.
Nick Larsen

+1 Bukan untuk lekukan aktual ini, tetapi ini adalah solusi terbaik untuk contoh ini .
Mark Hurd

2
Hanya pemformatan otomatis tak disengaja lainnya yang akan menghapus semua indentasi, dan waktu untuk putaran restrukturisasi - sangat produktif :)
nawfal

2

Jauh dari kejahatan, operator ternary adalah anugerah.

  • Ini sangat berguna ketika Anda ingin membuat keputusan dalam ekspresi bersarang . Contoh klasiknya adalah panggilan fungsi:

    printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
    
  • Dalam contoh khusus Anda, ternary hampir serampangan, karena itu adalah ekspresi tingkat atas di bawah a return. Anda dapat mengangkat persyaratan ke tingkat pernyataan tanpa menduplikasi apa pun selain returnkata kunci.

NB Tidak akan ada yang membuat algoritma khusus untuk median mudah dibaca.


Sulit untuk dibaca sehingga Anda tidak bisa membuatnya lebih baik. printf("I see %d evil construct%s in this program\n", n, "s" unless (n == 1) "s");
Pacerier

2
  1. Di samping argumen "Jahat", dalam pengalaman saya, saya telah menemukan korelasi yang tinggi antara seorang programmer yang menggunakan operator ternary dan kemungkinan seluruh basis kode menjadi sulit untuk dibaca, diikuti, dan dipelihara (jika tidak langsung tidak berdokumen). Jika seorang programmer lebih peduli dengan menyimpan beberapa baris karakter 1-2 daripada seseorang yang dapat memahami kode nya, maka setiap kebingungan kecil memahami pernyataan ternary biasanya adalah puncak gunung es.

  2. Operator ternary menarik angka ajaib seperti s ** t menarik lalat.

Jika saya sedang mencari perpustakaan Open Source untuk memecahkan masalah tertentu, dan saya melihat kode seperti operator ternary poster asli dalam kandidat untuk kata perpustakaan, lonceng peringatan akan mulai berbunyi di kepala saya dan saya akan mulai mempertimbangkan untuk pindah ke beberapa proyek lain untuk meminjam.


2

Berikut ini adalah contoh dari ketika adalah kejahatan:

oldValue = newValue >= 0 ? newValue : oldValue;

Ini membingungkan dan boros. Kompiler dapat mengoptimalkan ekspresi kedua (oldValue = oldValue), tetapi mengapa koder melakukan ini di tempat pertama?

Doozy lain:

thingie = otherThingie != null ? otherThingie : null;

Beberapa orang tidak dimaksudkan untuk menjadi pembuat kode ...

Greg mengatakan itu setara jika pernyataannya 'berisik'. Itu jika Anda menulisnya dengan berisik. Tetapi itu sama jika dapat ditulis sebagai:

if ('a' == $s) return 1;
if ('b' == $s) return 2;
if ('c' == $s) return 3;
return 4;

Yang tidak ribut dari ternary. Saya ingin tahu apakah jalan pintas ternary; apakah semua ekspresi dapat dievaluasi?


Contoh kedua Anda mengingatkan saya pada if (x != 0) x = 0;...
fredoverflow

2

Jahat? Lihat, mereka hanya berbeda.

ifadalah sebuah pernyataan. (test ? a : b)adalah sebuah ekspresi. Mereka bukan hal yang sama.

Ekspresi ada untuk mengekspresikan nilai. Pernyataan ada untuk melakukan tindakan. Ekspresi dapat muncul di dalam pernyataan, tetapi tidak sebaliknya. Jadi, Anda dapat menggunakan ekspresi ternary dalam ekspresi lain, seperti untuk istilah dalam penjumlahan, atau untuk argumen ke metode, dan sebagainya. Anda tidak harus , tetapi Anda bisa jika mau . Tidak ada yang salah dengan itu. Beberapa orang mungkin mengatakan itu jahat, tapi itu pendapat mereka.

Salah satu nilai dari ekspresi ternary adalah membuat Anda menangani kasus benar dan salah. ifpernyataan tidak.

Jika Anda khawatir tentang keterbacaan, Anda dapat memformatnya agar dapat dibaca.

Entah bagaimana "jahat" masuk ke kosa kata pemrograman. Saya ingin tahu siapa yang pertama menjatuhkannya. (Sebenarnya, saya punya tersangka - dia ada di MIT.) Saya lebih suka kita memiliki alasan obyektif untuk penilaian nilai dalam bidang ini, bukan hanya selera dan panggilan nama orang.


1
Bolehkah saya memberi petunjuk siapa tersangka itu? Hanya untuk meningkatkan pengetahuan saya tentang bidang sedikit.
mlvljr

1
@mlvljr: Ya saya bisa saja salah, jadi lebih baik tidak melakukannya.
Mike Dunlavey

1

Itu punya tempat. Saya telah bekerja di banyak perusahaan di mana tingkat keterampilan pengembang berkisar dari mengerikan hingga penyihir. Karena kode harus dipelihara, dan saya tidak akan berada di sana selamanya, saya mencoba menulis hal-hal sehingga terlihat seperti miliknya di sana (tanpa melihat komentar dengan inisial saya, sangat jarang bagi Anda untuk dapat lihat kode yang telah saya kerjakan untuk melihat di mana saya membuat perubahan), dan seseorang dengan keterampilan kurang dari saya dapat mempertahankannya.

Sementara operator ternary terlihat nitziffic dan keren, pengalaman saya adalah bahwa baris kode tidak mungkin dipertahankan. Di perusahaan saya saat ini, kami memiliki produk yang telah dikirim selama hampir 20 tahun. Saya tidak akan menggunakan contoh itu di mana pun.


1

Saya tidak berpikir bahwa operator ternary itu jahat.

Tapi di sini ada gotcha yang membuatku bingung. Saya adalah seorang programmer C untuk banyak (10+) dan pada akhir 1990-an saya pindah ke pemrograman aplikasi berbasis web. Sebagai seorang programmer web, saya segera berlari di PHP yang juga memiliki operator ternary. Saya memiliki bug dalam program PHP yang akhirnya saya telusuri ke baris kode dengan operator ternary bersarang. Ternyata operator ternary PHP terkait dari kiri ke kanan tetapi operator ternary C (yang dulu saya kenal) mengaitkan kanan ke kiri.


1

Apa pun yang membuat kode Anda lebih buruk adalah jahat.

Jika Anda menggunakan ternary untuk membuat kode Anda lebih bersih, maka pastikan menggunakannya. Terkadang dalam php seperti itu bagus untuk melakukan penggantian inline, misalnya

"Hello ".($Male?"Mr":"Ms")." $Name

Itu menghemat beberapa baris, dan itu cukup jelas, tetapi contoh Anda membutuhkan setidaknya pemformatan yang lebih baik untuk menjadi jelas, dan ternary tidak benar-benar baik untuk multi-line, maka Anda mungkin juga menggunakannya jika / selain itu.


1

Bisakah saya mengatakannya? Saya tidak dapat menemukan aplikasi jahat operasi ternary ini :

  1. operasi yang dilakukan sangat sepele, dan sekali Anda melewatinya sekali tidak mungkin beberapa bug akan keluar;
  2. apa yang dilakukannya secara jelas dinyatakan dalam nama fungsi;
  3. mengambil> 1 baris untuk sesuatu yang begitu jelas dan yang sangat jelas tidak akan ditingkatkan di masa depan (kecuali algoritma median sulap tidak terdeteksi sampai sekarang).

Tolong ampun, reputasi saya sudah cukup menyedihkan.


1

Kemenangan terbesar: Menunjukkan bahwa ada satu target aksi.

if ( $is_whatever )
    $foo = 'A';
else
    $foo = 'B';

Ada dua jalur kode yang dapat Anda ikuti, dan pembaca harus membaca dengan cermat untuk melihat dua variabel yang sedang diatur. Dalam hal ini, itu hanya satu variabel, tetapi pembaca memiliki lebih banyak membaca untuk mencari tahu. Bagaimanapun, bisa jadi ini:

if ( $is_whatever )
    $foo = 'A';
else
    $bar = 'B';

Dengan operator ternary, jelas bahwa hanya satu variabel yang ditetapkan.

$foo = $is_whatever ? 'A' : 'B';

Pada level yang paling rendah, ini adalah prinsip KERING (Jangan Ulangi Diri Sendiri) pada dasarnya. Jika Anda $foohanya dapat menentukan sekali, lakukan saja.


0

Jika ... maka ... lain cenderung menekankan kondisi dan karenanya tidak menekankan operasi yang dilakukan secara kondisional.

operator ternary adalah kebalikannya, ia cenderung menyembunyikan kondisi dan karenanya berguna ketika operasi yang dilakukan lebih penting daripada kondisi itu sendiri.

Ada gangguan teknis minor, dalam beberapa bahasa, bahwa mereka tidak cukup saling dipertukarkan karena satu menjadi pernyataan dan satu ekspresi misalnya konstelasi inisialisasi kondisional dalam C ++


0

Kapan tepat, dan kapan tidak?

Saya pikir ketika mengembangkan untuk sekelompok orang yang homogen, tidak ada masalah tetapi ketika Anda harus berurusan dengan orang-orang yang menangani level yang berbeda, oneliners semacam ini hanya memperkenalkan level kompleks lebih lanjut pada kode. Jadi, kebijakan saya tentang masalah ini adalah: kode jelas dan jangan jelaskan daripada kode pendek dan jelaskan 123123 kali.

Haruskah itu diajarkan atau disembunyikan dari pemula?

Saya seharusnya tidak diajari untuk pemula, lebih memilih mereka untuk mencari tahu ketika perlu muncul, jadi itu akan digunakan hanya ketika diperlukan dan tidak setiap kali Anda membutuhkan jika.


0

IMO, operator itu sendiri tidak jahat, tetapi sintaks yang digunakan untuk itu dalam C (dan C ++) terlalu singkat. IMO, Algol 60 melakukannya dengan lebih baik, jadi sesuatu seperti ini:

A = x == y ? B : C;

akan terlihat lebih seperti ini (tetapi secara umum tetap menggunakan sintaksis mirip-C):

A = if (x==y) B else C;

Bahkan dengan itu, bersarang yang terlalu dalam dapat menyebabkan masalah dengan keterbacaan, tetapi setidaknya A) siapa pun yang melakukan pemrograman sama sekali dapat mengetahuinya dengan sederhana, dan B) orang yang memahaminya dapat menangani sarang yang jauh lebih dalam dengan cukup mudah. OTOH, saya juga mencatat bahwa dalam LISP (misalnya) a condcukup banyak seperti pernyataan ternary - bukan seperangkat pernyataan, tetapi satu ekspresi menghasilkan nilai (sekali lagi, sebagian besar LISP seperti itu .. .)


Mengapa tidak lakukan ini saja agar mudah dibaca? A = (x==y) ? B : C
Jeremy Heiler

@Jeremy: sementara beberapa orang menganggap parens berguna, bahkan paling-paling mereka tidak banyak membantu . Bersarang lebih dari satu pasangan dan Anda masih perlu lekukan hati-hati (minimal) untuk menjaga keadaan. Tidak diragukan lagi hal yang sama akan terjadi pada akhirnya di Algol, tetapi saya tidak pernah mengatakan masalah muncul di dalamnya seperti yang sering saya lakukan di C ...
Jerry Coffin

Saya hanya berasumsi semua orang setuju bahwa bersarang operator ternary itu buruk. Saya berbicara secara khusus tentang contoh yang Anda berikan. Secara khusus, bagaimana yang pertama bisa lebih seperti yang kedua di sebagian besar bahasa.
Jeremy Heiler

0

Sebuah toko yang secara teratur menulis metode 600-1200-line seharusnya tidak memberi tahu saya bahwa ternary "sulit untuk dipahami". Setiap toko yang secara teratur mengizinkan lima kondisi untuk mengevaluasi cabang kode tidak boleh memberi tahu saya bahwa kondisi yang diringkas secara konkret di suatu terner adalah "sulit dibaca".


0

Kapan?: Tepat, dan kapan tidak?

  • Jika Anda tidak mendapatkan peningkatan kinerja, jangan gunakan; itu mempengaruhi keterbacaan kode Anda.
  • Gunakan sekali dan jangan bersarang.
  • Lebih sulit untuk di-debug.

Haruskah itu diajarkan atau disembunyikan dari pemula?

Tidak masalah, tetapi tidak boleh disembunyikan dengan sengaja karena tidak terlalu rumit untuk dipelajari oleh seorang "pemula".


-2

Dalam contoh Anda:

def median(a, b, c):
    if a < b < c: return b
    if a < c < b: return c
    if b < a < c: return a
    if b < c < a: return c
    if c < a < b: return a
    if c < b < a: return b

sangat mudah dibaca, dan jelas. Variabel antara <<adalah nilai kembali.

Memperbarui

sama, tetapi lebih sedikit baris kode. Masih sederhana menurut saya.

def median(a, b, c):
    if b<a<c or c<a<b: return a
    if a<b<c or c<b<a: return b
    if a<c<b or b<c<a: return c

Ini membutuhkan 12 perbandingan dalam kasus terburuk ...
fredoverflow

1
Mungkin, tapi itu bisa terbaca.
Christopher Mahan

-2

Itu juga perlu untuk const

const int nLegs  = isChicken ? 2: 4 ;

Aneh. Saya pikir itu C ++ atau sesuatu. Saya pikir const selalu mengkompilasi konstanta waktu (seperti dalam C #)
nawfal

@nawfal - jika Anda tidak tahu isChicken sampai runtime
Martin Beckett

ya itu apa. saya pikir constbegitu dalam bahasa tertentu. Dalam C # constharus selalu kompilasi nilai diketahui waktu. yang berarti const int nLegs = isChicken ? 2: 4 ;tidak akan bekerja, tetapi const int nLegs = true ? 2: 4 ;akan
nawfal
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.