Üçlü operatör zararlı olarak kabul edildi? [kapalı]


79

Örneğin, bu tek astarı tercih eder misiniz?

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;
}

ya da çoklu iade ifadeleri içeren if / else çözümü?

Ne zaman ?:uygun, ne zaman uygun değil? Yeni başlayanlara öğretilmeli veya gizlenmeli mi?


221
Bu özel kullanım :)
karmajunkie

6
Bunu kim kodladı ve dört sayı için ortanca versiyonları nasıl görünüyor? Veya beş?
Mason Wheeler

3
Daha doğru isim 'koşullu operatör'. Bu sadece kullanılan en yaygın üçlü operatör olur.
Alan Pearce,

1
Bu iki yıl önce yığın akışında istendi. Burada her şeyi tekrar soracağız mı? stackoverflow.com/questions/160218/to-ternary-or-not-to-ternary
webbiedave

3
Neden böyle soruların ortaya çıkmasına şaşırdım. Cevap her zaman "ne işe yarar ve okunabilir" olur. - Sonuncusu eşit derecede önemli.
Apoorv Khurasia

Yanıtlar:


234

Üçlü operatör kötü mü?

Hayır, bu bir lütuf.

Ne zaman?: Uygun mu?

Bu kadar basit bir şey olduğunda, çok fazla satır atmak istemezsiniz.

ve ne zaman değil?

Kodun okunabilirliği ve açıklığı acı çekiyorsa ve yetersiz dikkat nedeniyle bir hata potansiyeli artarsa, örneğin, tıpkı örneğinizde olduğu gibi birçok zincirleme operatörü ile birlikte.


Litmus testi, kodunuzun uzun vadede kolayca okunabilir ve bakımının yapıldığından şüphe etmeye başladığınız zamandır. O zaman yapma.


23
Kodun okunabilirliği ve açıklığının olması durumunda +1 . Pek çok zincirleme operatörü ile aynı örnekte olduğu gibi. Örnek, / başkasının eşdeğerinden daha anlaşılması daha uzun sürer.
44'te

23
Büyük açıklama için +1 bravo! Geliştiriciler, bazı şeylerin yargı çağrıları olduğunu anlama eğiliminde değildir, her şeyin siyah beyaz olmasını isterler. Beni deli ediyor. “X şeytan, asla kullanmamalıyız” düşüncesiyle birçok insanla karşılaştım. "X’in iyi olması için kullanıyorsanız harikadır" ı tercih ederim.
Monica

54
Eğer kullanılıyorsa, aynı zamanda kötü: myVar = (someExpression)? doğru yanlış; Aaaaarrgh!
adamk

20
@ adamk: Bunu kötülük için deneyin:myVar = someExpression ? false : true;
Dean Harding

8
Peki ya (someExpression ? var1 : var2)++:-)
fredoverflow

50

Bence reddedilmemiş üçlü operatör (sadece bir kez kullanıldığı bir ifade) gayet iyi, ama birden fazla iç içe geçiyorsanız okunması biraz zorlaşıyor.


3
Bu bir basitleştirme olarak kabul edilebilir, ancak takip edilmesi çok kolay bir rehberdir ve çoğu durumda işe yarar.
Alan Pearce

2
Bu aslında benim kuralımdır: onları asla yuvalamamalısın, aksi takdirde / başkasıyla değiştir, bu şekilde daha açık olacaktır.
Piovezan,

Onları kullanır ve iç içe yerleştirirseniz, insanlığın aşkı için parantez ve beyaz alanın okunmasını sağlamak için kullanın. Eğer başka bir çirkin yapılabilir. Derleyicilerin okuyabildiği, ancak insanların okuyamadığı şeyleri yazarak ne kadar 'akıllı' olduğunuzu gösterme dürtüsüne direnç gösterin. Bir gün, yapamayan insan olacaksın.
candied_orange

24

Ne zaman?: Uygun

  • Kodunuzu daha özlü ve okunabilir hale getirdiğinde.

ve ne zaman değil?

  • Kodunuzu okunamaz hale getirdiğinde.
  • Eğer bunu sadece kodu yapmak zorunda olan kişiye değil, ReSharper gibi bir yeniden düzenleme aracı yapmak için yapıyorsanız

Üçlü ifadenin içinde herhangi bir mantık veya işlev çağrısı varsa, onu incelemeyi korkunç hale getirirsiniz.


Bu, çok fazla oy hakediyor!
Piovezan,

22

(Bence) kimsenin işaret etmediği bir fark, üçlü operatörün yapabileceği başka bir değerin geri dönemediğidir.

F # 'dan gelince, bazen desen eşleştirmesini taklit etmek için üçlü operatörü kullanmak istiyorum.

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

vs

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

Bu oldukça havalı. Bunu asla düşünmedim.
Rei Miyasaka

+1 @Benjol: Aynı şeyi işaret edecektim (F # 'da her şey if / elif / else de dahil olmak üzere bir ifadedir). Ben de senin örneğinde olduğu gibi ternarileri kullanıyorum, şimdiye dek de keşfedilmemiş :). Javascript'te belki de en üstte yaptığım bir diğer şey ise: var res = function() {switch(input) {case 1: return "1"; case 2: return "2"; ...}}()anahtarları ifadeler olarak taklit etmek.
Stephen Swensen,

@Stephen, ben kelimeleri kullanmak gidiyordu expressionve statementama her zaman endişeliyim ben yuvarlak onları yanlış yola olsun ve :) kendimi aptal durumuna yapacağız
Benjol

@ Benjol: Ne demek istediğini biliyorum!
Stephen Swensen

6
Ayrıca C ve C ++ ' constda daha sonra değiştirilemeyen değişkenleri başlatmak için kullanışlıdır .
David Thornley,

13

Geçerli bir kullanım örneği (IMHO):

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

Bu, 2 farklı baskı ifadesine sahip olmaktan daha fazla okunabilir kodla sonuçlanır. İç içe örnekler aşağıdakilere bağlıdır: (anlaşılabilir? Evet: hayır)


11
Sadece bunu yaparsanız, başvurunuzu yerelleştirmek zorunda kalanlar için cehenneme çevirdiğinizi unutmayın. Tabii ki, eğer sorun değilse, devam et.
Anon.

1
Bu benim kuralım: 1 iç içe geçme düzeyi (bazı durumlarda).
Oliver Weiler,

7

Kesinlikle kötü değil. Aslında, saf ve eğer-o zaman-başka-değil.

Haskell, F #, ML vb. Gibi işlevsel dillerde, kötü sayılan if-then-else ifadeleridir.

Bunun nedeni, zorunlu if-then-else ifadesi gibi herhangi bir "işlem" in, değişken bir bildirimi tanımından ayırmanızı gerektirdiğini ve işlevinize durumu tanıttığını olmasıdır .

Örneğin, aşağıdaki kodda:

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

vs.

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

İlki, kısa olmanın yanında iki avantaja sahiptir:

  1. x bir sabittir ve bu yüzden böcekleri ortaya koyma şansı çok daha azdır ve potansiyel olarak ikincinin asla olamayacağı şekilde optimize edilebilir.
  2. Tür, ifade ile netleştirilmiştir, bu nedenle derleyici xtürünün olması gerekmediğini zahmetsizce çıkartabilir Parity.

Kafa karıştırıcı bir şekilde, işlevsel dillerde, üçlü operatör genellikle if-then-else olarak adlandırılır. Haskell'de söyleyebilirsin x = if n mod 3 == 1 then Odd else Even.


evet, bu @ Benjol'de yapılan nokta. Javascript'te ifadeler olarak switch ifadelerini öykünmenin eğlenceli bir yolu için verdiği cevaba yorumuma bakın.
Stephen Swensen,

7

Bu ifade, gözlerimin acıtmasına neden oluyor; Ekibimdeki herhangi bir geliştiriciyi kullanmazdım çünkü kullanılamaz bir durumdaydı.

Üçlü operatörler iyi kullanıldığında kötülük değildir. Tek satır olmaları bile gerekmez; İyi biçimlendirilmiş bir uzun olanı çok net ve anlaşılması kolay olabilir:

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

Bunu / sonra / else zincirindeki eşdeğerden daha çok seviyorum:

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

return $retval;

Bunları yeniden biçimlendireceğim:

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

return $retval;

Koşullar ve ödevler kolay hizalamaya izin veriyorsa. Yine de üçlü versiyonu tercih ediyorum çünkü daha kısa ve şartlar ve görevler etrafında fazla gürültü yok.


Neden yorum yazıları ekleyemiyorum? Arrgghh!
Christopher Mahan

3

ReSharper VS.NET içinde bazen yerine anlaşılacağı if...elseile ?:operatör.

ReSharper'ın sadece şartların / blokların belirli bir karmaşıklık seviyesinin altında kalmasını önerdiğini gösteriyor, aksi halde yapışıyor if...else.


4
ReSharper'ı çok sevdiğim bir diğer harika özellik
Anonymous Type

2

Bu, if / else birleşimi kadar güzel görünümlü olacak şekilde yeniden biçimlendirilebilir:

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;
}

Ancak sorun şu ki, gerçekte ne olacağını temsil etmek için girinti hakkına sahip olup olmadığımdan emin değilim. :-)


3
+1 Bunun eşdeğer bir if-elseyapıdan çok daha iyi olduğunu düşünüyorum . Anahtar biçimlendirmedir.
Orbling

13
Bunu bir kod tabanında görseydim, ciddi bir şekilde yeni bir iş aramayı düşünürdüm.
Nick Larsen

+1 Bu gerçek girinti için değil, ancak bu örnek için en iyi çözüm .
Mark Hurd

2
Sadece bir başka yanlışlıkla otomatik biçimlendirme tüm bu girintileri ve başka bir yeniden yapılandırma turu için zamanı - oldukça verimli :)
nawfal

2

Kötü olmaktan uzak, üçlü operatör bir nimettir.

  • Yuvalanmış bir ifadeyle karar vermek istediğinizde en kullanışlıdır . Klasik örnek bir işlev çağrısıdır:

    printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
    
  • Özel örneğinizde, üçlü, a'nın altındaki en üst düzey ifade olduğundan, neredeyse gereksizdir return. returnAnahtar kelimeden başka bir şeyi çoğaltmadan koşullu ifadeyi ifade düzeyine kaldırabilirsiniz .

NB Hiç bir şey, medyan için bu özel algoritmayı okumayı kolaylaştıramaz.


Daha iyi yapamayacağınız kadar okunaklı olmak zor. printf("I see %d evil construct%s in this program\n", n, "s" unless (n == 1) "s");
Pacerier

2
  1. "Kötülük" argümanlarını bir kenara koydum, tecrübelerime göre bir programcının üç operatörünü kullanması ile kod kodlarının tamamının okunması, takip edilmesi ve bakımı zor olma olasılığı (belgesiz değilse) arasında yüksek bir korelasyon buldum. Eğer bir programcı birinin kodunu anlayabilmesinden 1-2 karakterlik bir kaç satır tasarruf etmekle daha fazla ilgileniyorsa, üçlü bir ifadeyi anlayan herhangi bir küçük karışıklık genellikle buzdağının tepesidir.

  2. Üçlü operatörler sinekleri çeken s * gibi sihirli sayıları çeker.

Belirli bir sorunu çözmek için bir Açık Kaynak kütüphanesi arıyor olsaydım ve söz konusu kütüphane için bir adaydaki orijinal posterin üçlü operatörleri gibi bir kod görürsem, uyarı zilleri kafamdan akmaya başlardı ve devam etmeyi düşünürdüm ödünç alınacak başka bir projeye.


2

İşte ne zaman bir örnek olduğunu kötülük:

oldValue = newValue >= 0 ? newValue : oldValue;

Kafa karıştırıcı ve israflıdır. Derleyici ikinci ifadeyi optimize edebilir (oldValue = oldValue), ama kodlayıcı bunu neden ilk başta yaptı?

Başka bir Doozy:

thingie = otherThingie != null ? otherThingie : null;

Bazı insanlar kodlayıcı olmak zorunda değildir.

Greg, eğer ifadenin 'gürültülü' olduğunu söylüyor. Gürültülü bir şekilde yazarsanız. Ancak aynı şekilde yazılabilirse:

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

Üçlüden daha gürültülü değil. Üçlü kısayollar olup olmadığını merak ediyorum; ifadelerin tümü değerlendiriliyor mu?


İkinci örneğiniz bana hatırlatıyor if (x != 0) x = 0;...
fredoverflow

2

Evil? Bak, sadece farklılar.

ifbir ifadedir. (test ? a : b)bir ifadedir. Aynı şey değiller.

İfadeler değerleri ifade etmek için vardır. İşlem yapmak için açıklamalar var. İfadeler ifadelerin içinde görünebilir ancak bunun tersi olmaz. Böylece, toplam ifadelerdeki terimler veya bir yönteme olan argümanlar gibi diğer ifadelerdeki üçlü ifadeleri kullanabilirsiniz. Sen yok zorunda ama istersen eğer . Bunda yanlış bir şey yok. Bazı insanlar bunun kötü olduğunu söyleyebilir, ama bu onların düşüncesi.

Üçlü ifadenin bir değeri, hem gerçek hem de yanlış durumları ele almanızı sağlar. ififadeler yok.

Okunabilirlikten endişeleniyorsanız bunları kolayca biçimlendirebilirsiniz.

Her nasılsa "kötülük" programlama sözlüğüne çarptı. İlk kimin düşürdüğünü bilmek isterdim. (Aslında, bir şüpheliyim - o MIT'de.) Sadece halkların zevkine ve isim söylemesine değil, bu alandaki değer yargılarının nesnel nedenlerine sahip olmayı tercih ederim.


1
Şüphelinin kim olduğu hakkında bir ipucu alabilir miyim? Sadece alan bilgimi biraz geliştirmek için.
mlvljr

1
@mlvljr: Yanlış olabilirim, o yüzden yapmamak daha iyi.
Mike Dunlavey

1

Bir yeri var. Geliştiricilerin yetenek seviyelerinin korkunçtan büyücüye kadar değiştiği birçok şirkette çalıştım. Kodun muhafaza edilmesi gerektiğinden ve sonsuza dek orada olamayacağımdan, oraya ait gibi görünmesi için bir şeyler yazmaya çalışıyorum (baş harflerle yaptığım yorumlara bakmadan, yapabilmeniz çok nadirdir. Nerede değişiklik yaptığımı görmek için üzerinde çalıştığım koda bakın) ve kendimden daha az beceriye sahip birisinin bunu sürdürebileceğini.

Üçlü operatör dikkat çekici ve çok havalı görünmekle birlikte, benim deneyimim kod satırının korunmasının imkansız olacağı yönünde. Şu andaki işverenimde neredeyse 20 yıldır nakliye yapan ürünlerimiz var. Bu örneği hiçbir yerde kullanmam.


1

Üçlü operatörün kötü olduğunu düşünmüyorum.

İşte beni güldüren bir kaçık. Birçok (10+) C programcısıydım ve 1990'ların sonunda web tabanlı uygulama programlamasına geçtim. Bir web programcısı olarak, yakında üçlü bir operatör olan PHP ile de karşılaştım. Bir PHP programında, iç içe geçmiş bir üçlü operatörle kod satırına kadar takip ettiğim bir hatam vardı. PHP üçlü operatörünün soldan sağa ilişkilendirildiği, ancak C üçlü operatörünün (kullandığım) sağdan sola ilişkilendirildiği ortaya çıktı.


1

Kodunuzu çirkin yapan her şey kötüdür.

Kodunuzu daha temiz hale getirmek için üçlü kullanıyorsanız kullandığınızdan emin olun. Bazen php gibi, satır içi değişimler yapmak harika, örn.

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

Bu, birkaç satır kazandırır ve oldukça açıktır, ancak örneğinizin en azından daha iyi biçimlendirmeye ihtiyacı vardır ve üçlü, çoklu satır için gerçekten iyi değildir, o zaman / / if kullanabilirsiniz.


1

Söyleyebilir miyim? Üçlü operasyon kötülüğünün bu özel uygulamasını bulamadım :

  1. gerçekleştirdiği işlem oldukça önemsiz ve bir kez çıldırdığınızda, bazı hataların ortaya çıkması pek mümkün değil;
  2. işlev isminde açıkça belirtildiği;
  3. Bu kadar belirgin bir şey için> 1 satır almak ve gelecekte net bir şekilde iyileştirilmeyecek (sihirli bir medyan algoritması bugüne kadar tespit edilmemişse).

Lütfen merhamet et, ünüm zaten çok acınacak.


1

En büyük kazanç: Tek bir hareket hedefi olduğunu göstermek.

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

İzleyebileceğiniz iki kod yolu vardır ve hangi iki değişkenin ayarlandığını görmek için okuyucunun dikkatlice okuması gerekir. Bu durumda, sadece bir değişkendir, ancak okuyucunun bunu anlamak için okuması gereken daha çok şeyi vardır. Sonuçta, bu olabilirdi:

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

Üçlü operatör ile sadece bir değişkenin ayarlandığı açıktır.

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

En düşük seviyede, en temel olan DRY (Kendinizi Tekrar Etmeyin) ilkesidir. $fooYalnızca bir kez belirtebilirsiniz , bunu yapın.


0

Eğer ... o zaman ... başkası durumu vurgulamaya ve dolayısıyla şartlı olarak yapılan operasyonları altını çizmeye meyillidir.

Üçlü operatör tam tersidir, durumu gizleme eğilimindedir ve bu nedenle yapılan işlem koşulun kendisinden daha önemli olduğunda yararlıdır.

Bazı dillerde, bir ifade ve diğeri ifadesi nedeniyle C:


0

Ne zaman uygun, ne zaman uygun değil?

Bence homojen bir grup insan için geliştirilirken sorun yok, ancak farklı seviyelerde çalışan insanlarla uğraşmak zorunda kaldığınızda, bu tür onellerin sadece koda daha ileri düzeyde bir karmaşıklık kattığını düşünüyorum. Bu yüzden, konuyla ilgili politikam şu: kod açık değil kod açık ve açık değil ve 123123 defa açıklayın.

Yeni başlayanlara öğretilmeli veya gizlenmeli mi?

Yeni başlayanlara öğretilmemeli, ihtiyaç duyulduğunda ortaya çıkmalarını anlamalarını tercih etmeliyim, bu yüzden sadece gerekli olduğunda ve bir ifşaya ihtiyacınız olduğunda kullanılamaz.


0

IMO, operatörün kendisi kötü değil, ancak C (ve C ++) 'da kullanılan sözdizimi aşırı derecede özlü. IMO, Algol 60 daha iyisini yaptı, şöyle ki:

A = x == y ? B : C;

daha çok şuna benzeyecekti (ancak genel olarak C benzeri sözdizimine bağlı kalarak):

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

Bununla birlikte, aşırı derin yuvalar okunabilirlikle ilgili sorunlara yol açabilir, ancak en azından A) hiç programlama yapan herkes basit bir çözüm bulabilir ve B) bunu anlayanlar oldukça derin yuvalamayı oldukça kolay bir şekilde kaldırabilir. OTOH, ayrıca, LISP'de (örneğin) conda'nın üçlü bir ifadeye çok benzer olduğunu - bir dizi ifadenin değil, ancak tek bir ifadenin bir değer verdiğini (daha sonra, LISP'nin çoğunun böyle olduğunu ..) .)


Neden bunu sadece okunabilirlik için yapmıyorsun? A = (x==y) ? B : C
Jeremy Heiler

@ Jeremy: Bazı insanlar parenleri faydalı bulurken, en iyi ihtimalle pek yardımcı olmuyorlar . Birkaç derinlemeden daha fazla yuva yapın ve işleri düzenli tutmak için yine de dikkatlice çentiklenmeye (asgari olarak) ihtiyacınız var. Kuşkusuz, aynı şey Algol'da da olur, ama hiçbir zaman C de sık sık yaptığım gibi bir problem ortaya çıkmaz demem ...
Jerry Coffin,

Herkesin bir üçlü operatörün yuva yapmasının kötü olduğu konusunda hemfikir olduğunu varsaydım. Özellikle verdiğin örnekler hakkında konuşuyordum. Özellikle, birincisinin bir çok dilde ikinciye nasıl daha çok benzeyebileceği.
Jeremy Heiler

0

Bir dükkan düzenli 600-1200 satırlı yöntemlerini yazıyor olmamalıdır bir üçlü "anlaşılması zor" olduğunu söyle. Herhangi dükkan düzenli beş koşullar bir kod şube değerlendirmenize olanak sağlar olmamalı bana bir Üçlü o somut özetlenen koşulları anlatmak "okumak zor" dir.


0

Ne zaman?: Uygun ve ne zaman değildir?

  • Bir performans kazancı elde etmezseniz, kullanmayın; kodunuzun okunabilirliğini etkiler.
  • Bir kez kullanın ve iç içe geçirmeyin.
  • Hata ayıklamak daha zor.

Yeni başlayanlara öğretilmeli veya gizlenmeli mi?

Önemi yok, ama “yeni başlayan” ın öğrenmesi için çok karmaşık olmadığı için kasıtlı olarak gizlenmemelidir.


-2

Örnekte:

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

okunması çok basit ve açık. <<Arasındaki değişken, dönüş değeridir.

Güncelleme

Aynı, ancak daha az kod satırı. Hala basit düşünüyorum.

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

Bu en kötü durumda 12 karşılaştırma yapılmasını gerektirir ...
fredoverflow

1
Belki, ama okunaklı.
Christopher Mahan

-2

Const için de gerekli

const int nLegs  = isChicken ? 2: 4 ;

Garip. C ++ ya da bir şey düşünüyorum.
Const'un

@nawfal - isChicken'ı çalışma zamanına kadar bilmiyorsanız
Martin Beckett

evet bu ne. bence constbazı dillerde öyle. C # consther zaman bilinen değeri derleme olmalıdır. Bu const int nLegs = isChicken ? 2: 4 ;işe yaramayacak, ama const int nLegs = true ? 2: 4 ;olacak
nawfal
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.