삼항 운영자는 해로운 것으로 간주? [닫은]


79

예를 들어,이 단일 라이너를 선호합니까

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

또는 여러 반환 문이 포함 된 if / else 솔루션입니까?

?:적절한 시기는 언제 입니까? 초보자에게 가르쳐야하거나 숨겨야합니까?


221
그것의 특별한 사용은 :)
karmajunkie

6
누가 그것을 코딩했으며, 4 개의 숫자에 대한 중간 값은 어떻게 생겼습니까? 아니면 다섯?
메이슨 휠러

3
더 정확한 이름은 '조건부 연산자'입니다. 사용중인 가장 일반적인 삼항 연산자입니다.
Alan Pearce

1
이것은 2 년 전에 stackoverflow에 대해 물었습니다. 우리는 지금 여기에 모든 것을 다시 물어볼 것입니까? stackoverflow.com/questions/160218/to-ternary-or-not-to-ternary
webbiedave

3
왜 그런 질문이 계속 나오는지 놀랐습니다. 답은 항상 "작동하는 것과 읽을 수있는 것"입니다. -마지막으로 중요하다.
Apoorv Khurasia

답변:


234

삼항 연산자는 사악합니까?

아니요 축복입니다.

언제? : 적절한가?

그것이 너무 간단한 일이라면 많은 줄을 낭비하고 싶지 않습니다.

언제 그렇지 않습니까?

코드의 가독성과 명료성이 떨어지고 예를 들어 많은 체인 연산자가 예를 들어 불충분 한주의를 기울이면 실수가 발생할 가능성이 높아집니다.


리트머스 테스트는 장기적으로 코드를 쉽게 읽고 유지 관리 할 수 ​​있는지 의심하기 시작합니다. 그런 다음하지 마십시오.


23
코드의 가독성과 선명도가 떨어지는 경우 +1 예제와 같이 많은 체인 연산자가 있습니다. 예제는 동등한 if / else보다 이해하는 데 더 오래 걸립니다.
sange

23
훌륭한 설명을 위해 +1 브라보! 개발자들은 어떤 것이 판단 요청이라는 것을 깨닫지 못하고 모든 것이 흑백이되기를 원합니다. 그것은 나를 미치게합니다. 나는 많은 사람들에게 "X는 악하다, 절대로 사용하지 말자"라는 의견을 만났다. 나는 "X가 좋다면 X를 사용하면 좋을 것"을 선호한다.
닥터 존스

54
그것이 사용된다면 그것은 또한 악하다 : myVar = (someExpression)? 허위 사실; 아아아 아아아!
adamk

20
@adamk : 악을 위해 이것을 시도하십시오 :myVar = someExpression ? false : true;
Dean Harding

8
어떻습니까 (someExpression ? var1 : var2)++:-)
fredoverflow

50

나는 중첩되지 않은 삼항 연산자 (즉, 한 번만 사용되는 명령문)는 괜찮다고 생각하지만 둘 이상 중첩하면 읽기가 다소 어려워집니다.


3
이것은 지나치게 단순화 된 것으로 간주 될 수 있지만 따르기 매우 쉬운 지침이며 대부분의 경우 작동합니다.
Alan Pearce

2
실제로 내 경험 법칙입니다. 중첩하지 않아야합니다. 그렇지 않으면 if / else로 대체하면 더 명확합니다.
Piovezan

당신이 그것들을 사용하고 그것들을 중첩 시키려면 인류의 사랑을 위해 괄호와 공백을 사용하여 읽을 수있게하십시오. 그렇지 않으면 추악한 것처럼 만들 수 있습니다. 컴파일러가 읽을 수는 있지만 사람은 읽을 수없는 것을 작성하여 '똑똑한'모습을 보여 주려는 충동에 저항하십시오. 언젠가 당신은 할 수없는 인간이 될 것입니다.
candied_orange

24

언제? : 적절한

  • 코드를보다 간결하고 읽기 쉽게 만들 때

언제 그렇지 않습니까?

  • 코드를 읽을 수 없게 만드는 경우.
  • 코드를 관리 해야하는 사람이 아닌 ReSharper와 같은 리팩토링 도구를 기쁘게하기 위해이 작업을 수행하는 경우

삼항 표현식 내에 논리 또는 함수 호출이 있으면보기가 끔찍합니다.


이것은 많은 찬사를받을 가치가 있습니다!
Piovezan

22

아무도 지적하지 않은 한 가지 차이점은 if-else는 값을 반환 할 수 없지만 삼항 연산자는 반환 할 수 없다는 것입니다.

F #에서 왔을 때, 때때로 삼항 연산자를 사용하여 패턴 일치를 모방하고 싶습니다.

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

vs

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

꽤 괜찮은데. 그런 생각은하지 않았다.
Rei Miyasaka

+1 @Benjol : 나는 똑같은 것을 지적 할 것입니다 (F #에서는 모든 것이 if / elif / else를 포함한 표현입니다). 나는 당신의 예제와 같이 삼항을 사용하지만 지금까지도 발견되지 않았습니다 :). Javascript에서 아마도 상단에있는 다른 작업은 var res = function() {switch(input) {case 1: return "1"; case 2: return "2"; ...}}()스위치를 표현식으로 에뮬레이트하는 것입니다.
Stephen Swensen

@Stephen, 나는 단어를 사용하는 거라고 expressionstatement하지만 난 항상 걱정 나는 라운드 그들에게 길을 잘못 얻을 :) 자신의 바보 만들거야
Benjol

@Benjol : 무슨 말인지 알 겠어!
Stephen Swensen

6
또한 const나중에 변경할 수없는 변수 를 초기화하는 데 C 및 C ++에서 유용합니다 .
David Thornley

13

유효한 사용 예 (IMHO) :

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

결과적으로 2 개의 고유 한 인쇄 명령문을 사용하는 것보다 더 읽기 쉬운 코드가 생성됩니다. 중첩 된 예제는 다음에 의존합니다. (이해할 수 있습니까? 예 : 아니오)


11
이 작업을 수행하면 응용 프로그램을 현지화해야하는 사람이 누구에게나 도움이됩니다. 물론 문제가되지 않는다면 바로 진행하십시오.
아논.

1
내 경험에 따르면 1 단계 중첩 (일부 상황에서는).
Oliver Weiler

7

절대로 악하지 않습니다. 사실, 그것은 순수 하고 그렇지 않으면 그렇지 않습니다.

Haskell, F #, ML 등과 같은 기능적 언어에서는 사악한 것으로 간주되는 if-then-else 문입니다.

그 이유는 명령형 if-then-else 문과 같은 "조치"는 변수 선언과 정의를 분리해야하고 상태 를 함수에 도입 하기 때문입니다.

예를 들어 다음 코드에서

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

vs.

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

첫 번째는 더 짧은 것 외에 두 가지 장점이 있습니다.

  1. x 일정하며 버그를 도입 할 가능성이 훨씬 적으며, 두 번째로는 결코 할 수없는 방식으로 최적화 될 수 있습니다.
  2. 식에 의해 형식이 명확 해 지므로 컴파일러는 x형식 이 필요한 것을 쉽게 유추 할 수 있습니다 Parity.

혼란스럽게도 기능적 언어에서 삼항 연산자는 종종 if-then-else라고합니다. 하스켈에서는이라고 말할 수 있습니다 x = if n mod 3 == 1 then Odd else Even.


@, 이것은 @Benjol이 만든 요점입니다. Javascript에서 스위치 문을 표현식으로 에뮬레이트하는 재미있는 방법은 그의 답변에 대한 내 의견을 참조하십시오.
Stephen Swensen

7

그 특별한 표현은 내 눈을 아프게합니다. 유지 보수가 불가능하기 때문에 팀에서 사용한 모든 개발자를 래시합니다.

삼항 연산자는 잘 사용될 때 악하지 않습니다. 심지어 한 줄일 필요도 없습니다. 형식이 긴 긴 것은 매우 명확하고 이해하기 쉽습니다.

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

나는 동등한 if / then / else 체인보다 그것을 좋아합니다.

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

return $retval;

나는 그것들을 다음과 같이 다시 포맷 할 것이다 :

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

return $retval;

조건과 과제가 쉬운 정렬을 허용하는 경우. 여전히 나는 삼원 버전이 더 짧고 조건과 과제에 대해 소음이 적기 때문에 선호합니다.


주석에 줄 바꿈을 넣을 수없는 이유는 무엇입니까? 아아!
Christopher Mahan

3

ReSharper에서 VS.NET에서 때때로 교체 제안 if...else?:운영자.

ReSharper는 조건 / 차단이 특정 복잡도 수준 미만인 경우에만 제안하는 것으로 보이며 그렇지 않은 경우 계속 표시됩니다 if...else.


4
내가 ReSharper에 대해 좋아하는 또 다른 훌륭한 기능
Anonymous Type

2

이것은 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;
}

그러나 문제는 실제로 일어날 일을 나타낼 수있는 들여 쓰기 권한이 있는지 확실하지 않다는 것입니다. :-)


3
+1 나는 이것이 동등한 if-else구조 보다 훨씬 낫다고 생각합니다 . 열쇠는 형식입니다.
Orbling

13
코드베이스에서 이것을 본다면 새로운 일자리를 찾는 것을 진지하게 고려할 것입니다.
Nick Larsen

이 실제 들여 쓰기 +1,하지만이에 대한 최상의 솔루션 예.
Mark Hurd

2
만 다른 사고 자동 서식은 구조 조정의 또 다른 라운드에 대한 모든 것을 들여 쓰기, 시간을 쓸어 것 - 거대 생산 :
nawfal

2

삼항 연산자는 악이 아니라 신의 선물입니다.

  • 중첩 식에서 결정을 내릴 때 가장 유용 합니다. 전형적인 예는 함수 호출입니다.

    printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
    
  • 특정 예에서 삼항은에 대한 최상위 표현식이므로 거의 무의미합니다 return. return키워드 이외의 다른 항목을 복제하지 않고도 조건부를 명령문 레벨로 해제 할 수 있습니다 .

NB 어떤 것도 중간 값을 쉽게 읽을 수있는 특정 알고리즘을 만들 수 없습니다.


읽기가 어려워서 더 나아질 수는 없습니다. printf("I see %d evil construct%s in this program\n", n, "s" unless (n == 1) "s");
Pacerier

2
  1. "사악한"주장을 제외하고는 필자의 경험에 따르면 프로그래머의 삼항 연산자 사용과 전체 코드베이스를 읽고 따르고 유지하기가 어려울 가능성 (문서화되지 않은 경우) 사이에 높은 상관 관계가 있음을 발견했습니다. 프로그래머가 자신의 코드를 이해할 수있는 사람보다 1-2 자 정도의 문자를 저장하는 데 더 관심이있는 경우, 3 진법을 이해하는 사소한 혼란은 대개 빙산의 일각입니다.

  2. 삼항 연산자는 s ** t가 파리를 끌어 당기는 것처럼 마법의 숫자를 끌어들입니다.

특정 문제를 해결하기 위해 오픈 소스 라이브러리를 찾고 있었는데 해당 라이브러리의 후보에서 원래 포스터의 삼항 연산자와 같은 코드를 보았을 때 경고 벨이 내 머리에서 떨어지기 시작하고 계속 진행하기 시작했습니다. 빌릴 다른 프로젝트에.


2

다음 악한 경우의 예입니다 .

oldValue = newValue >= 0 ? newValue : oldValue;

혼란스럽고 낭비입니다. 컴파일러 는 두 번째 표현식 (oldValue = oldValue)을 최적화 할 수 있지만 코더는 왜 처음에 이것을 했습니까?

또 다른 doozy :

thingie = otherThingie != null ? otherThingie : null;

어떤 사람들은 코더가되어서는 안됩니다 ...

Greg는 동등한 if 문이 '잡음'이라고 말합니다. 당신이 그것을 시끄럽게 쓰는 경우입니다. 그러나 다음과 같이 쓸 수 있다면 동일합니다.

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

삼항보다 더 시끄럽지 않습니다. 삼항 지름길인지 궁금합니다. 모든 표현이 평가됩니까?


두 번째 예는 생각 나게 if (x != 0) x = 0;...
fredoverflow

2

악? 봐, 그들은 단지 다르다.

if진술입니다. (test ? a : b)식입니다. 그들은 같은 것이 아닙니다.

값을 표현하기위한 표현이 존재합니다. 조치를 수행하기위한 명령문이 있습니다. 문 안에식이 나타날 수 있지만 그 반대는 아닙니다. 따라서 요약의 용어 또는 메서드의 인수 등과 같은 다른 식 내에서 삼항 식을 사용할 수 있습니다. 당신은하지 않습니다 에있다 , 그러나 당신은 당신이 원하는 수있는 경우 . 그것에 아무런 문제가 없습니다. 어떤 사람들은 그것이 악하다고 말하지만 그것은 그들의 의견입니다.

삼항 표현식의 한 가지 가치는 대 / 소문자를 모두 처리 할 수 ​​있다는 것입니다. if진술하지 않습니다.

가독성이 걱정되면 쉽게 읽을 수 있도록 형식을 지정할 수 있습니다.

어떻게 든 "악한"프로그래밍 어휘에 들어갔다. 누가 먼저 떨어 뜨 렸는지 알고 싶습니다. (실제로, 나는 용의자가 있습니다-그는 MIT에 있습니다.) 오히려 우리는 사람들의 취향과 이름을 부르는 것만이 아니라이 분야에서 가치 판단의 객관적인 이유를 갖고 싶습니다.


1
용의자가 누구인지 힌트를 주시겠습니까? 현장 지식을 조금만 향상시키기 위해서입니다.
mlvljr

1
@ mlvljr : 글쎄, 내가 틀릴 수 있으므로 그렇게하지 않는 것이 좋습니다.
Mike Dunlavey가

1

장소가 있습니다. 나는 개발자의 기술 수준이 끔찍한 마법사에서 마법사에 이르기까지 많은 회사에서 근무했습니다. 코드를 유지 관리하고 영원히 거기에 있지 않기 때문에 코드가 속하는 것처럼 보이도록 항목을 작성하려고합니다 (내 이니셜로 주석을 보지 않고는 거의 할 수 없습니다. 내가 변경 한 위치를 확인하기 위해 작업 한 코드를 살펴보십시오.

삼항 연산자가 열광적이고 멋지게 보이지만 내 경험에 따르면 코드 줄을 유지 관리하기가 거의 불가능합니다. 현재 고용주에게는 거의 20 년 동안 배송 된 제품이 있습니다. 나는 그 예제를 어디에도 사용하지 않을 것이다.


1

나는 삼항 연산자가 악하다고 생각하지 않습니다.

그래도 저를 엉망으로 만들었습니다. 저는 많은 (10+)의 C 프로그래머였으며 1990 년대 후반에 웹 기반 응용 프로그램 프로그래밍으로 옮겼습니다. 웹 프로그래머로서 나는 삼항 연산자를 가진 PHP를 곧 보았습니다. PHP 프로그램에 버그가있어서 마침내 중첩 된 삼항 연산자로 코드 줄을 추적했습니다. PHP 삼항 연산자는 왼쪽에서 오른쪽으로 연결되었지만 C 삼항 연산자 (내가 익숙했던)는 오른쪽에서 왼쪽으로 연결됩니다.


1

코드를 추악하게 만드는 것은 사악합니다.

삼항을 사용하여 코드를 더 깨끗하게 만들면 반드시 사용하십시오. 때로는 PHP와 같이 인라인 대체를 수행하는 것이 좋습니다.

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

이렇게하면 몇 줄이 절약되고 꽤 명확하지만 예제는 적어도 더 나은 서식을 지정해야하며 삼항은 여러 줄에 적합하지 않으므로 if / else를 사용할 수도 있습니다.


1

말할 수 있습니까? 나는 삼항 작업이 특정 응용 프로그램을 찾을 관리 할 수 악을 :

  1. 그것이 수행하는 작업은 매우 사소한 것이며 일단 일단 통과하면 거의 불가능할 수도 있습니다.
  2. 기능 이름에 명확하게 명시되어 있습니다.
  3. 마법의 중간 알고리즘이 지금까지 발견되지 않은 한, 분명하고 무언가를 위해 1 줄 이상을 가져 가면 미래에는 분명히 개선되지 않을 것입니다.

자비를 베풀어주세요. 제 평판은 이미 불쌍합니다.


1

가장 큰 승리 : 단일 행동 목표가 있음을 보여줍니다.

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

따라갈 수있는 두 가지 코드 경로가 있으며 독자는 두 변수를 설정하기 위해주의해서 읽어야합니다. 이 경우에는 하나의 변수 일 뿐이지 만 독자는이를 이해하기 위해 더 읽어야합니다. 결국, 이것은 다음과 같을 수 있습니다.

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

삼항 연산자를 사용하면 하나의 변수 만 설정됩니다.

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

가장 낮은 수준에서는 가장 기본적으로 DRY (Do n't Repeat Yourself) 원칙입니다. $foo한 번만 지정할 수 있으면 지정하십시오 .


0

만약 그렇다면 ... 그렇지 않으면 ...은 조건을 강조하고 따라서 조건부로 수행되는 작업을 강조하지 않는 경향이 있습니다.

삼항 연산자는 반대이며 조건을 숨기는 경향이 있으므로 수행되는 작업이 조건 자체보다 더 중요 할 때 유용합니다.

일부 언어에서는 기술적 인 조건이 하나 있는데, 하나는 문장이기 때문에 하나의 표현과 하나의 표현으로 인해 상호 교환이 불가능하다는 것입니다.


0

적절한시기는 언제입니까?

나는 균질 한 사람들 그룹을 위해 개발할 때 아무런 문제가 없지만 다른 수준을 다루는 사람들을 다루어야 할 때, 이런 종류의 oneliners는 코드에 더 복잡한 수준을 도입 할 뿐이라고 생각합니다. 그래서 문제에 대한 나의 정책은 다음과 같습니다.

초보자에게 가르쳐야하거나 숨겨야합니까?

나는 초보자에게 가르쳐서는 안되며, 필요할 때 알아내는 것을 선호하므로 필요할 때마다 필요하지 않을 때 필요할 때만 사용됩니다.


0

연산자 자체는 악의가 없지만 C (및 C ++)에서 사용되는 구문은 너무 간결합니다. IMO, Algol 60이 더 잘 했으므로 다음과 같이하십시오.

A = x == y ? B : C;

다음과 같이 보일 것입니다 (그러나 일반적으로 C와 같은 구문을 고수하십시오).

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

그럼에도 불구하고 과도한 중첩은 가독성에 문제를 일으킬 수 있지만 적어도 A) 프로그래밍을 한 사람은 누구나 간단한 것으로 파악할 수 있으며 B) 이해하는 사람들은 상당히 깊은 중첩을 쉽게 처리 할 수 ​​있습니다. OTOH, 나는 또한 LISP에서 (예를 들어) a cond는 문장의 집합이 아니라 삼항 문장과 거의 비슷하지만 단일 표현식은 값을 산출합니다 (다시 말하면, 대부분의 LISP는 그와 같습니다.) .)


가독성을 위해 왜 이것을하지 않습니까? A = (x==y) ? B : C
Jeremy Heiler

@Jeremy : 어떤 사람들은, 괄호 유용하면서 심지어 가장 그들은 도움이되지 않습니다 많은 . 몇 개 이상 깊게 둥지를 틀어도 물건을 정리하려면 조심스럽게 들여 쓰기해야합니다 (최소한). 의심 할 여지없이 같은 일이 결국 Algol에서도 일어날 것입니다. 그러나 저는 C에서 자주하는 것처럼 문제가 발생한다고 결코 말하지 않습니다.
Jerry Coffin

방금 삼항 연산자를 중첩하는 것이 나쁘다는 데 모든 사람이 동의했다고 가정했습니다. 나는 당신이 제공 한 예에 대해 구체적으로 말하고있었습니다. 특히, 첫 번째 언어가 대부분의 언어에서 두 번째 언어와 비슷할 수 있습니다.
Jeremy Heiler

0

600-1200 줄의 방법 을 정기적으로 쓰는 상점 은 3 진법이 이해하기 어렵다고 말해서 는 안됩니다 . 코드 브랜치를 평가하기 위해 5 가지 조건을 정기적으로 허용 하는 모든 상점 에서는 3 항의 구체적으로 요약 된 조건이 "읽기가 어렵다"고 말해서 는 안됩니다 .


0

?는 언제 적절한가?

  • 성능이 향상되지 않으면 사용하지 마십시오. 코드의 가독성에 영향을줍니다.
  • 한 번만 사용하고 중첩하지 마십시오.
  • 디버깅하기가 더 어렵습니다.

초보자에게 가르쳐야하거나 숨겨야합니까?

중요하지 않지만 "초보자"가 배우기에는 너무 복잡하지 않으므로 의도적으로 숨겨서는 안됩니다.


-2

귀하의 예에서 :

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

읽기 쉽고 명확합니다. <<사이의 변수는 반환 값입니다.

최신 정보

동일하지만 더 적은 코드 줄. 여전히 간단하다고 생각합니다.

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

최악의 경우에 12 번의 비교가 필요합니다.
fredoverflow

1
아마도, 그러나 읽을 수 있습니다.
Christopher Mahan

-2

const에도 필요합니다.

const int nLegs  = isChicken ? 2: 4 ;

이상한. 나는 그 C ++ 또는 무언가를 생각합니다. 나는 const가 항상 컴파일 타임 상수 (C #
에서처럼

@nawfal-런타임까지 isChicken을 모른다면
Martin Beckett

그렇습니다. const특정 언어에서는 그렇게 생각 합니다. C #에서는 const항상 컴파일 타임 알려진 값이어야합니다. 그 말은 const int nLegs = isChicken ? 2: 4 ;늘 일을하지만 const int nLegs = true ? 2: 4 ;
nawfal
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.