프로그래밍 언어의 설계 원칙
- 언어 설계의 기본 원칙 : 효율성(Efficiency), 일반성(Generality), 직교성(Orthogonality), 획일성(Uniformity)
- 기타 설계 원칙 : 간결성(Simplicity), 표현력(Expressiveness), 정확성(Preciseness), 기계 독립성(Machine Independence), 안전성(Security), 기존 표기나 규칙과의 일관성, 확장성(Extensibility), 제약성(restrictability), 부분성(Subset)
-
일반성, 직교성, 획일성은 매우 밀접한 관계이다.
-
효율성
- 목적 코드의 효율성 : 번역기가 효율적인 실행 코드를 생성할 수 있어야함을 의미
- 번역기의 효율적 실행 코드 생성 -> 최적화
- ex) Pascal에서 상수는 수식으로 표현되지 않고 번역 과정에서 배정된 값으로 대체된다.
- 번역기의 효율적 실행 코드 생성 -> 최적화
- 번역의 효율성 : 번역기가 효율적으로 실행 코드를 생성할 수 있어야함을 의미
- 적절한 크기의 번역기로 빠르게 번역할 수 있는 것
- ex) 언어 번역의 단계 구성 문제 - Pascal : 단일 패스, Modula-2 : 2 패스
- 적절한 크기의 번역기로 빠르게 번역할 수 있는 것
- 구현 용이성 : 번역기를 효율적으로 작성할 수 있어야 한다.
- 번역기의 효율적인 구현 문제
- ex) ALGOL 60은 번역기 구현이 어렵거나 번역 수행 알고리즘이 충분히 이해되지 않아 언어가 성공하지 못했다.
- 번역기의 효율적인 구현 문제
- 프로그래밍 효율성 : 설계된 언어로 얼마나 빠르고 쉽게 프로그램을 작성할 수 있어야 함을 의미
- 프로그램 작성의 단순성, 용이성 문제
- 언어의 표현성, 추상화 메커니즘과 관련
- 이상적인 언어 - LISP, PROLOG
- 목적 코드의 효율성 : 번역기가 효율적인 실행 코드를 생성할 수 있어야함을 의미
-
일반성
- 특별한 경우를 피하고 밀접하게 관련있는 개념들을 하나의 더 일반적인 것으로 결합하는 성질
- 대입 연산자(=, :=)가 배열과 레코드를 비롯한 모든 데이터 타입에 적용되는 경우
- 비일반성 : 문맥과 관계없는 제한
- 일반성이 부족한 예
- 프로시저
- Pascal : 프로시저 선언과 매개 변수 허용, 프로시저형 변수 불허
- Modula-2 : 일반성을 갖는다.
- Ada : 매개 변수에 프로시저를 사용할 수 없다.
- 배열
- Pascal : 가변 배열 불허
- C, Ada : 가변 배열 허용
- Modula-2, FORTRAN : 가변 배열 전달 능력, 가변 배열 선언 불허
- 동등 연산자, 배정 연산자 (=, :=) : 대부분의 언어는 배열, 레코드에 적용하지 않지만 Ada는 적용했다.
- 매개 변수
- FORTRAN : call-by-reference만 허용
- ALGOL 68, C, Java : call-by-value, 객체에 대한 포인터를 값으로 전달 가능, 일반성 제공
- Ada : 일반성 제공
- 상수
- FORTRAN : 상수 이름 부재
- Pascal : 상수 표현에 수식 사용 불가
- Ada : 일반성 갖춘 상수 제공
- 프로시저
- 일반성이 갖는 문제점
- 언어의 간결성, 판독성, 신뢰성 저하
- ex) C언어의 포인터(일반성 제공) - 문제점 제기
- Java는 포인터 불허를 통해 신뢰성과 판독성 문제 해결
- Pascal에서는 이명(Aliasing)과 위험을 줄이기 위해 포인터가 본질적으로 제한된다.
-
직교성
- ‘직각 또는 완전히 독립적인 방향’을 의미하는 수학의 직교성 새념에서 유래
- 언어의 구성자들이 각각의 의미를 가진 채 결합하는 성질
- 한 언어의 구성자가 문맥이 다르다고 다른 의미를 가져서는 안 된다는 성질
- 구성자 간의 상호작용 또는 문맥의 사용이 예상 밖의 행위를 야기하지 않아야 한다.
- 매개변수 전달에 있어서 데이터 타입에 상관없이 동일한 전달 방식을 지원하는 경우
- 비직교성 : 문맥에 의존하는 제한
- 직교성이 부족한 예
- 함수 반환값 자료형
- Pascal : 스칼라형, 포인터형만 허용
- C : 배열형만 제외
- Ada : 완벽한 직교성 제공 (모든 자료형 허용)
- 파일
- Pascal : 파일형은 특별한 상태 취급 (파일을 프로시저 매개 변수로 전달 금지, 파일 변수는 배정 금지)
- 대부분의 언어는 파일을 라이브러리로 취급한다.(비직교성 탈피)
- 문자열
- Modula-2 : 문자열 배정 (작은 문자열 -> 더 큰 문자열)
- 크기가 다른 객체에 대한 유일한 배정
- 매개변수 전달 기법
- C : 배열 - call-by-reference, 배열 이외의 모든 자료형 - call-by-value
- Ada : 모든 자료형 - call-by-value, result, value-result 허용(직교성 보장)
- 함수 반환값 자료형
- ALGOL 68의 중요 설계 목표는 직교성 보장이었다.
-
획일성
-
비슷한 것은 비슷하게 보이고 비슷한 의미를 가져야 하며, 다른 것은 다르게 보이고 다른 의미를 가져야 한다는 원칙
-
언어 구조들의 외모와 행동에서의 조화에 중점을 둔다.
-
획일성이 부족한 예 : C++에서 클래스 정의와 함수 정의
-
획일성이 부족한 비조화의 예 (Pascal)
-
if문, while문 : begin-end 구조 요구
-
repeat문 : begin-end 구조 비요구
-
가변 레코드에서 case문, case 제어문 : 구문 상이 (Modula-2에서 해결)
-
함수 값의 반환 방법 - 배정문과 유사 (타 언어들은 return으로 해결)
-
function f : boolean; begin ... f := true; end;
-
-
↑ : 포인터 선언(↑integer)과 포인터 값(x↑)에 똑같은 문자로 쓰인다.(Modula-2는 POINTER TO로 해결)
-
세미콜론(;) : Modula-2, Pascal에서 문장 구분자와 선언 종결자로 사용한다.(C언어에서는 종결자로만 쓰인다.)
-
procedure p; (* terminator *) var x : integer; (* seperator *) y : real; (* seperator *) begin x := 0; (* seperator *) y := 1.0; (* seperator *) end; (* terminator *)
-
-
-
비획일성은 특별한 문맥에서만 발생되고 구성자들 간의 상호작용을 볼 수 있으므로 비직교성으로 간주될 수도 있다.
-
-
간결성
- 언어가 복잡하지 않고 간결해야함을 의미
- LISP와 Prolog 등은 단지 몇 개의 기본 구성자를 가지고 있다.
- Pascal의 주된 설계 원칙은 간결성이다.
- 직교성, 일반성, 획일성 : 간결성을 보장하지 못한다. (ex : ALGOL 68)
- 구성자의 수가 적다고 언어가 간결한 것은 아니다. (ex : LISP, PROLOG는 적은 수의 구성자를 가지지만 복잡한 실행 시간과 시스템에 의존적이다.)
- 과다한 단순성은 언어 사용에 방해되고, 표현력이 부족하며, 많은 제한이 발생된다.
-
표현력
-
언어가 복잡한 과정이나 구조를 얼마나 쉽게 표현할 수 있는가를 의미
-
표현력은 강하나 단순하지 않은 언어 - LISP, PROLOG, ALGOL 68
-
표현력이 강하면서 단순한 언어 - C
-
ex)
-
while(*s++ == *t++);
-
-
-
LISP와 ALGOL 60 등의 재귀(Recursion)
-
(defun factorial (n) (if (= n 0) 1 (* n (factorial (- n 1)))))
-
-
표현력은 간결성과 상충될 수 있다.
-
-
확장성 (Extensibility)
- 사용자가 언어에 새로운 기능을 추가할 수 있도록 하는 성질
- 사용자가 새로운 타입을 정의하는 것, 라이브러리에 새로운 함수를 추가하는 것, 번역기에 새로운 키워드를 추가하는 것 등등
- 확장성을 가진 언어의 예 - LISP
- 명령형 언어는 함수형 언어보다 언어 확장이 어려움
- 추상화 개념(자료 추상화, 제어 추상화)은 확장성을 지원한다.
-
정확성
- 프로그램의 실행을 예측할 수 있도록 하는 언어에 대한 정확한 정의가 있는지를 의미한다.
- 언어에 대한 정확한 정의는 프로그램과 번역기의 신뢰성과 언어의 행위가 예측 가능한 정의의 존재 여부에 영향을 미친다.
-
기계 독립성
- 언어가 특정 기계에 의존적이지 않고 독립적인 것을 의미한다.
- 메모리 할당이나 기계 구조 등의 내용과는 독립적인 미리 정의된 데이터 타입을 제공하는 것.
- 기계 독립적인 언어 정의를 통하여 보장한다. (호환성 제공)
-
제약성(Restrictabliity), 부분성(Subset)
- 언어에 대한 최소한의 지식과 일부 언어 구조만을 알고 있더라도 프로그램을 작성할 수 있다는 성질
- 언어 제한성의 장점
- 프로그래머는 언어의 효과적인 사용을 위해 언어 전체를 배울 필요가 없다.
- 번역기 작성자가 언어 일부분만을 선택하여 구현하고 사용이 가능하다.(부분 언어 지원)
- ex) SP/1, SP/2, …, SP/K : PL/I의 부분 언어들
-
보안성(안전성, Security)
- 프로그래밍 오류를 줄이고 오류 발견을 쉽게 하는 언어를 설계하는 원칙
- 신뢰성과 정확성에 밀접한 연관을 가지고 프로그래머가 범할 수 있는 오류의 수를 최소화하자는 것
- 언어 설계 시 자료형, 형 검사, 변수 선언을 도입
-
기존 표기나 규칙과의 일관성
- 언어 설계 시 표준화된 특성과 개념을 갖도록 해야 한다.
- ex) ALGOL 68 - 표준화된 표기를 잘 따르지 않았다. (type 대신 mode 사용)
- 성공적인 언어 설계
- 신뢰성
- 프로그램의 신뢰성을 위해 진단 컴파일러 또는 점검 컴파일러 사용
- Cornell : PL/I diagnostic, C언어 환경(debugger 포함)
- 효율적인 번역
- 초기 고급 언어(FORTRAN, COBOL, …) : 분리 컴파일 제공 -> 효율적 번역 가능, 오류 유발
- ALGOL 68, Pascal(1970년대 초반) : 신뢰성 강조 -> 통합 컴파일러 -> Ada : 조화 (분리 컴파일의 장점 + 통합 컴파일의 장점), specification part, body part 제공으로 해결
- 코드 최적화(Optimization)
- 효율적인 목적 코드
- 컴파일링 비용 증가
- 반복 수행부 등 일부분만 최적화 -> 효과 증대
- 실제 컴파일러들은 여러 최적화 단계를 제공한다.
- 신뢰성
- 언어 구문의 과다한 간결성과 생략은 프로그램 판독성을 저하
- 적절한 수준의 간결성은 프로그래머에게 좋은 훈련이 되며 프로그램의 신뢰성을 증가시킨다.
- APL과 4세개 언어는 짧은 프로그램이지만 신뢰성을 증진시켰다.
- 신뢰성
- C. A. R. Hoare의 성공적인 프로그래밍 언어 설계를 위한 충고
- 언어의 특정한 특성(feature) 고안
- 새 특성의 설계자는 한 번에 한 가지 특성에 집중
- 잘 알려진 언어의 특성 구현
- 이미 존재하는 언어의 장점을 해치지 않고, 언어의 단점과 불완전성을 해결, 완화한다.
- 이 특성들이 어떻게 단순하고, 효율적으로 구현되는지 보여야 한다.
- 사용자 지침서 작성
- 많은 예제 프로그램들을 작성해서 다른 방법들과 비교 평가한다.
- 새로운 언어 설계 (기존 특성들을 선택, 조합)
- 기존의 많은 특성들 : 숙지, 선택, 판단력 구비
- 특성들 사이의 불일치를 제거하고 중첩 부분을 조정해야 한다.
- 새 언어의 영역, 목적, 범위, 복잡성, 확장성에 대한 명확한 개념이 필요하다.
- 실제 구현과 사용자 지침서(초보자용, 고급용)를 제공해야 한다.
- 새 언어 설계 작업은 단지 기존의 개념을 통합하는 것
- 언어의 특정한 특성(feature) 고안