왼쪽에서 오른쪽 언어 구문의 장점


18

나는 Channel9 에서 Herb Sutter와의 인터뷰를 보았고 비디오 끝에서 왼쪽에서 오른쪽으로 언어 구문이 미래의 C ++ 표준에 대한 그의 기발한 목록에서 맨 위에 올 것이라고 언급했다. 완전히 다른 짐승을 만들 것입니다).

와는 별개로:

  • 육안으로보다 명확하게 인간이 이해할 수있는 것; 예.

    //C syntax
    
    /*pointer to function taking a pointer to function(which takes 2 integers as 
    
    arguments and returns an int), and an int as arguments and returning an int*/
    
    int (*fp)(int (*ff)(int x, int y), int b)
    
    //Go analogous syntax which is left to write
    
    f func(func(int,int) int, int) int
  • 파싱하기 쉬움 (비디오에서 언급 한 바와 같이 도구 지원 향상-코드 리팩토링)

프로그래밍 언어에서 "왼쪽에서 오른쪽으로"구문이있는 다른 장점은 무엇입니까? 나는 그런 종류의 구문을 사용하는 Pascal과 Go에 대해서만 알고 있습니다 (그리고이 블로그 게시물 에서 이해 한 것처럼 Go도 완벽하게 진행되지 않습니다 ). 그런 종류의 시스템 프로그래밍 언어를 갖는 것이 가능할까요? 구문


1
하스켈 사용은 왼쪽에서 오른쪽으로 :f :: (Int -> Int -> Int) -> Int -> Int
카 롤리 바스

1
ActionScript : function strlen(s:String):int {...}. 또한 람다 미적분학을 입력했습니다 (따라서 Haskell).
outis

2
누구든지 마감 투표를 설명해 주시겠습니까? :) 닫는 이유를 알 수 없지만 "잘못된"질문을합니다.

1
나는 폐회하기 위해 투표하지 않았지만 @Devjosh의 의견은 적절합니다. 프로그래머에게 더 적합합니다. 누군가가 그것을 옮기기를 바랍니다 ....
Nim

3
@Frank : 함수 포인터의 경우, 실제 타입이 분리되어 있기 때문에 구문이 어색하다는 것을 잊지 마십시오 ! 그것은 낮은 타격입니다 ...
Matthieu M.

답변:


12

기본 장점은 구문 분석이 더 단순하고 고유하다는 것입니다. 행이 구문 분석 된 후 컴파일러는 정확한 유형이 무엇인지 알게되므로 거기서부터 유형이 어떻게 정의되었는지는 알 수 없습니다.

배열 유형의 인수 또는 함수 포인터 유형을 리턴하는 함수는 현재 읽기가 어렵습니다.

// common way of obtaining the static size in elements of an array:
template <typename T, int N>
char (&array_size_impl( T (&)[N] ))[N];
// alternative parser:
template <typename T, int N>               // this would probably be changed also
array_simple_impl function( T [N] & ) char [N] &;

그리고 오해의 가능성이 가장 적습니다 ( 가장 까다로운 구문 분석 ).

// Current C++
type x( another_type() );      // create an instance x of type passing a
                               // default constructed another_type temporary?
                               // or declare a function x that returns type and takes as argument
                               // a function that has no arguments and returns another_type
// How the compiler reads it:
x function( function() another_type ) type;

// What many people mean:
x type { another_type{} };

C ++ 0x에서 균일 한 초기화 (즉, {}초기화 식별)에 유사한 접근법을 사용합니다 . 왼쪽에서 오른쪽으로 접근하면 정의하는 것이 훨씬 명확 해집니다. 과거에이 파싱 오류로 인해 많은 사람들이 (물론 저에게) 물린 적이 있습니다 (왼쪽에서 오른쪽으로).


표현은 어떻습니까? 이 "왼쪽에서 오른쪽 구문"은 연산자 우선 순위 및 평가 순서에 어떤 영향을 미칩니 까?

1
@celavek : 인터뷰로 돌아 가면, 언어의 전체 구문을 바꾸고 싶지 않고 선언정의 만 바꾸고 싶다는 것을 알게 될 것 입니다. 물론, 그것은 다른 표현에 스며들 수 있습니다. 위 예제의 마지막 줄이 왼쪽에서 오른쪽으로 적절하다는 것을 확신하지 못합니다 (임시 생성 방법을 생각하십시오 .C #에서 변경해야 할 수도 있습니다 ... 받는 두 의미를 제공함으로써 해결된다 new위한 연산자 struct또는 classC ++과 C에 적용되지 않으며, ++ 값 / 참조 형식에 아무런 차이가 없다.
데이비드 로드리게스 - dribeas

5

우리가 어떻게 여기

기능 점을 선언하기위한 C 구문은 사용법을 반영하기위한 것입니다. 다음과 같은 정규 함수 선언을 고려하십시오 <math.h>.

double round(double number);

점 변수를 가지려면 다음을 사용하여 유형 안전으로 지정할 수 있습니다

fp = round;

fp이 방법으로 해당 점 변수를 선언해야합니다 .

double (*fp)(double number);

따라서 함수를 사용하는 방법을 살펴보고 해당 함수의 이름을 포인터 참조 round로 바꾸십시오 *fp. 그러나 여분의 파렌 세트가 필요합니다.

아마도 이것은 원래 C에서 더 쉬웠습니다. 기능 서명조차 없었지만 다시 돌아 가지 않습니까?

특히 불쾌한 곳은 인수로 사용하거나 함수에 대한 포인터를 반환하는 함수를 선언하는 방법 또는 둘 다를 결정하는 방법을 파악하는 것입니다.

기능이 있다면 :

void myhandler(int signo);

이 방법으로 신호 함수 (3)에 전달할 수 있습니다.

signal(SIGHUP, myhandler);

또는 이전 핸들러를 유지하려면

old_handler = signal(SIGHUP, new_handler);

꽤 쉽습니다. 아주 쉽고도 쉬운 것도 선언을 올바르게하는 것입니다.

signal(int signo, ???)

글쎄, 당신은 함수 선언으로 돌아가서 포인트 참조를 위해 이름을 바꾼다.

signal(int sendsig, void (*hisfunc)(int gotsig));

선언하지 않기 때문에 gotsig생략하면 더 쉽게 읽을 수 있습니다.

signal(int sendsig, void (*hisfunc)(int));

아니면 아닐 수도 있습니다. :(

signal (3)도 다음과 같이 이전 핸들러를 반환하기 때문에 충분하지 않습니다.

old_handler = signal(SIGHUP, new_handler);

이제 모든 것을 선언하는 방법을 알아야합니다.

void (*old_handler)(int gotsig);

할당하려는 변수에 충분합니다. gotsig여기서 실제로 선언하지는 않습니다 old_handler. 그래서 이것으로 충분합니다.

void (*old_handler)(int);

그러면 signal (3)에 대한 올바른 정의가 나타납니다.

void (*signal(int signo, void (*handler)(int)))(int);

구조에 Typedefs

이번에는 모든 사람들이 그것이 엉망이라는 데 동의 할 것이라고 생각합니다. 때로는 추상화의 이름을 지정하는 것이 좋습니다. 종종, 정말로. right를 사용하면 typedef이해하기가 훨씬 쉬워집니다.

typedef void (*sig_t) (int);

이제 자신의 핸들러 변수가됩니다.

sig_t old_handler, new_handler;

signal (3)에 대한 선언은

sig_t signal(int signo, sig_t handler);

갑자기 이해할 수 있습니다. *를 제거하면 혼란스러운 괄호도 제거됩니다 (그리고 그들은 parens가 항상 이해 하기 쉬워집니다 . 사용법은 여전히 ​​동일합니다.

old_handler = signal(SIGHUP, new_handler);

그러나 이제 old_handler,에 대한 선언을 이해하고 처음 접하게되거나 작성해야 할 때 new_handler조차 이해할 signal수 있습니다.

결론

아주 소수의 C 프로그래머, 알고 보니, 참고 자료상의없이 자신의 이러한 것들에 대한 올바른 선언을 고안 할 수있다.

커널과 장치 드라이버 작업을하는 사람들을위한 인터뷰 질문에이 질문이 있었기 때문에 알고 있습니다. :) 물론, 우리는 그들이 화이트 보드에 충돌하고 불에 타는 방식으로 많은 후보자를 잃었습니다. 그러나 우리는 또한이 분야에서 이전에 경험이 있다고 주장했지만 실제로는 일을 할 수없는 사람들을 고용하지 않았습니다.

그러나 이러한 광범위한 어려움으로 인해 더 이상 현명하지는 않지만 실제로는 이것을 사용하는 평균보다 세 시그마 위에 앉아있는 트리플 알파 괴짜 프로그래머가 아니어야하는 모든 선언에 대해 갈 수있는 방법을 갖는 것이 합리적입니다. 편안하게


1
비록 C에서 때때로 그 권리를 얻기가 어렵다는 점을 보여 주지만 노력을 위해 노력하기 위해 ... +1 노력했다.
celavek

4

왼쪽에서 오른쪽 비트에 집중했을 때 요점을 다소 놓쳤다 고 생각합니다.

C와 C ++의 문제는 그들이 가지고있는 끔찍한 문법으로, (사람)과 파싱 (도구) 모두 읽기가 어렵습니다.

보다 일관된 (또는 규칙적인 ) 문법을 사용하면 둘 다 더 쉬워집니다. 파싱이 쉬우면 툴링이 더 쉬워집니다. 대부분의 최신 도구는 C ++을 제대로 얻지 못합니다. Eclipse의 최신 플러그인조차도 바퀴를 재발 명하려고 시도했지만 실패했으며 아마도 평균 OS 프로젝트보다 많은 사람들이 있습니다.

그래서 당신은 아마 읽고 파싱에 집중할 때 그것을 못 박았을 것입니다 ... 그리고 그것은 큰 문제입니다 :)


이클립스가 여전히 위의 선언과 같은 것들을 파싱 할 수 없다는 것에 놀랍습니다. 왜 그들은 같은 실제 C 파서를 사용하지 gcc않습니까?
tchrist

@ tchrist : Eclipse에서 두 가지 문제를 발견했으며 매크로와 관련이있는 것 같습니다. 아마도 AST 생성보다 더 많은 전 처리기 문제 일 것입니다.
Matthieu M.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.