D 언어 사양 — 용어 사전
D 언어 사양 — 용어 사전 (Glossary)
D 언어 공식 사양의 마지막에 붙어 있는 '용어 사전(Glossary)' 챕터예요. 사양 본문 곳곳에서 쓰는 약어와 전문 용어를 한곳에 정리해 둔 곳이라, 문서를 읽다가 낯선 표현을 만나면 이 페이지를 열어 확인하면 됩니다. 각 용어는 영문 원래 이름과 정의를 함께 옮겨뒀어요. 나중에 영문 원문을 직접 찾아볼 때도 대응이 쉽도록요.
본문
ACC (Associated C Compiler) — 연관 C 컴파일러
D 컴파일러는 '연관 C 컴파일러(Associated C Compiler)'와 짝을 이뤄요. 예를 들어 Win32에서 ImportC는 Digital Mars C 컴파일러와 짝을 이루고, 명령줄 스위치 -m32mscoff를 쓰면 Visual C 컴파일러와도 연결할 수 있어요. Win64에서 ImportC는 Visual C 컴파일러와 짝을 이룹니다. Posix 대상에서는 Gnu C나 Clang C가 그 짝이 돼요.
BLIT (Block Transfer) — 블록 전송
BLT라고도 불리는 blit는 메모리를 바이트 하나하나 그대로 복사하는 것을 말해요. C에서는 이걸 memcpy 연산이라고 부르죠. 이름 자체는 DEC PDP-10 컴퓨터의 BLT 명령어에서 유래했어요.
CTFE (Compile Time Function Evaluation) — 컴파일 타임 함수 평가
일반적인 D 함수를 실행 시간(run time)이 아니라 컴파일 시간(compile time)에 실행할 수 있는 능력을 가리켜요.
Code Point — 코드 포인트
유니코드 용어에서 코드 포인트는 논리적인 문자 하나를 뜻해요. 코드 포인트의 범위는 0부터 0x10FFFF까지예요. 코드 포인트를 직접 저장할 수 있는 건 dchar뿐이고, char나 wchar 배열은 가변 길이 인코딩인 UTF-8과 UTF-16을 써야 해요.
COW (Copy On Write) — 쓰기 시 복사
COW는 참조 객체(보통 큰 것)를 수정하려 할 때만 복사하는 메모리 관리 전략이에요. COW의 고정 비용은 꽤 높을 수 있지만, 미리 복사를 많이 해두는 방식 대신 쓰는 게 더 유리한 애플리케이션도 있어요.
Data Race — 데이터 경쟁
둘 이상의 스레드가 같은 메모리 위치에 쓰기를 하는 상황을 말해요. 이때 프로그램 동작이 그 메모리 접근들의 임의적 실행 순서에 따라 달라질 수 있어요.
Functor — 펑터
**함수 호출 연산자(D에서는 opCall)를 정의해서 함수처럼 쓸 수 있게 만든 사용자 정의 타입(구조체나 클래스)**을 말해요.
GC (Garbage Collection) — 가비지 컬렉션
가비지 컬렉션은 '자동 메모리 관리(automatic memory management)'의 흔한 이름이에요. 메모리를 할당해 쓰면, GC가 더 이상 참조되지 않는 메모리 조각을 자동으로 해제해 줘요. 반대로 명시적 메모리 관리는 프로그래머가 할당 하나마다 정확히 한 번씩 free() 호출로 짝을 맞춰야 하는 방식이죠.
Higher-Order Function — 고차 함수
다른 함수를 매개변수로 받거나, 함수를 반환하거나, 둘 다 하는 함수를 말해요.
IES (Interpolated Expression Sequence) — 보간 표현식 시퀀스
문자열 리터럴과 표현식이 뒤섞여 있는 값의 시퀀스를 말해요. 자세한 내용은 사양 본문을 참고하세요.
IFTI (Implicit Function Template Instantiation) — 암묵적 함수 템플릿 인스턴스화
템플릿에 타입을 명시적으로 넘기지 않아도 템플릿 함수를 인스턴스화할 수 있는 능력을 가리켜요. 대신 타입은 런타임 인자들의 타입으로부터 자동으로 추론되죠. 자세한 내용은 사양 본문을 참고하세요.
Illegal — 비정상(위법)
어떤 코드 구성이 D 언어 사양을 따르지 않으면 illegal(비정상)이라 불러요. 컴파일러나 런타임이 그 오류를 감지하지 못하더라도 여전히 illegal일 수 있어요.
Input Range — 입력 범위
**멤버 함수 empty, front, popFront를 정의하는 타입(구조체나 클래스)**을 말해요. 입력 범위는 **엄격히 한 번만 통과(one-pass)**한다고 가정해요. 즉 범위의 복사본에 반복 상태를 저장하는 방법은 없죠. std.range도 함께 보세요.
Implementation-Defined Behavior — 구현 정의 동작
D 언어의 동작이 언어 구현자(implementor)에게 달려 있는 부분을 말해요. 대표적인 예가 포인터의 바이트 크기예요 — 32비트 머신에서는 4바이트, 64비트 머신에서는 8바이트죠. 언어에서 구현 정의 동작을 최소화할수록 코드의 이식성은 최대화돼요.
Lvalue — 좌변값
lvalue는 접근 가능한 주소를 가진 값을 가리키는 추상적인 용어예요(예를 들어 단항 & 연산자로 주소를 얻을 수 있는 값). 대표적인 lvalue로는 변수, const나 immutable로 도입한 상수(enum은 제외), 배열과 연관 배열의 요소가 있어요. ref를 반환하는 함수 호출과 포인터 역참조 표현식도 lvalue예요. lvalue는 참조(reference)로 함수에 전달하거나 함수에서 반환할 수 있어요. lvalue는 rvalue의 반대 개념이에요.
NRVO (Named Return Value Optimization) — 명명된 반환값 최적화
NRVO는 구조체 데이터의 복사를 최소화하기 위해 Walter Bright가 1991년경에 고안한 기법이에요(그 이름 자체는 나중에 붙었죠). 함수는 보통 반환값을 레지스터에 담아 돌려줘요. 그런데 구조체는 레지스터에 담기엔 너무 큰 경우가 많아요. 일반적인 해결책은 호출자의 스택 프레임에 있는 구조체 인스턴스를 가리키는 숨은 포인터를 함수에 넘기고, 거기에 반환값을 복사하는 거예요. 예를 들어:
struct S { int a, b, c, d; }
S foo() { S result; result.a = 3; return result; }
void test() { S s = foo(); }
이 코드는 다음과 같이 다시 쓰여요:
S* foo(S* hidden) { S result; result.a = 3; *hidden = result; return hidden; }
void test() { S tmp; S s = *foo(&tmp); }
이렇게 되면 임시 객체 tmp가 하나 더 생기고, 구조체 내용이 두 번 복사돼요. NRVO가 하는 일은 result의 유일한 목적이 반환값을 제공하는 것임을 알아채고, result를 가리키는 모든 참조를 *hidden으로 바꾸는 것이에요. 그러면 foo는 이렇게 다시 쓰여요:
S* foo(S* hidden) { hidden.a = 3; return hidden; }
foo 호출 쪽에서는 복사를 한 번 더 없애는 최적화가 이뤄져서:
void test() { S s; foo(&s); }
결과가 다른 두 인스턴스를 거치지 않고 목적지 s에 직접 쓰여요.
Narrow Strings — 내로우 문자열
char, wchar 그리고 그 한정(qualified) 버전을 쓰는 모든 배열은 narrow 문자열이에요. (string과 wstring도 여기 포함돼요.) 표준 라이브러리의 범위 지향 함수들은 UTF로 인코딩된 문자를 자동으로 디코딩하면서 내로우 문자열을 특별히 처리해요.
opApply — 오퍼레이터 애플라이
컬렉션을 순회하는 데 쓰는 특수 멤버 함수로, ForeachStatement(foreach 문)에서 사용돼요.
opApplyReverse — 리버스 오퍼레이터 애플라이
컬렉션을 역순으로 순회하는 데 쓰는 특수 멤버 함수로, ForeachStatement(foreach 문)에서 사용돼요.
POD (Plain Old Data) — 평범한 옛 데이터
숨은 멤버가 없고, 소멸자(destructor)가 없으며, 단순한 비트 복사로 초기화하고 복사할 수 있는 구조체를 말해요. 구조체(Structs) 관련 장을 함께 보세요.
Predicate — 술어
Boolean 결과를 반환하는 함수나 델리게이트를 말해요. 술어는 nullary(인자 없음), unary(인자 하나), binary(인자 둘), n-ary(인자 n개)일 수 있어요. 보통 술어는 술어를 매개변수로 받는 고차 함수의 맥락에서 언급돼요.
Qualifier-Convertible — 한정자 변환 가능
타입 T가 타입 U로 qualifier-convertible하다는 것은, 두 타입이 한정자(qualifier)에서만 다르고, 언어 규칙에 따라 T에 대한 참조가 U에 대한 참조로 암묵적으로 변환될 수 있을 때를 말해요.
RAII (Resource Acquisition Is Initialization) — 자원 획득 즉 초기화
RAII는 구조체나 클래스 객체가 유효 범위(scope)를 벗어날 때 그 소멸자를 호출하는 기법을 말해요. 소멸자는 그 객체가 획득한 자원을 해제하죠. RAII는 공급이 부족한 자원이나, 해제되는 시점을 예측 가능하게 해야 하는 자원에 흔히 써요. scope 저장 클래스로 선언한 클래스 변수에도 RAII를 적용할 수 있어요.
Rvalue — 우변값
rvalue는 접근 가능한 메모리 주소가 없는 표현식에서 나온 값을 가리키는 추상적인 용어예요. 이 주소 없음은 개념적인 것일 뿐이라, 구현이 rvalue를 주소 가능한 메모리에 저장할 자유는 있어요. rvalue는 변경할 수 없고, 참조로 함수에 전달하거나 함수에서 반환할 수도 없어요. rvalue는 lvalue의 반대 개념이에요.
Sequential Consistency — 순차 일관성
한 스레드에서 어떤 순서로 쓰인 데이터가, 다른 스레드에서도 같은 순서로 보이는 것을 말해요.
SFINAE (Substitution Failure Is Not An Error) — 치환 실패는 오류가 아님
템플릿 인자 추론의 결과가 유효하지 않은 타입이 되면, 그 템플릿의 해당 특수화는 더 이상 고려하지 않는다는 뜻이에요. 컴파일 오류는 아니죠. 관련 문서에서 SFINAE를 함께 참고하세요.
TMP (Template Metaprogramming) — 템플릿 메타프로그래밍
TMP는 언어의 템플릿 기능을 이용해 런타임이 아니라 컴파일 타임에 프로그램을 실행하는 것이에요.
TLS (Thread Local Storage) — 스레드 로컬 스토리지
TLS는 각 스레드에게 전역 데이터의 자기만의 인스턴스를 하나씩 할당해줘요. 관련 자료에서 Wikipedia 항목도 함께 보세요.
UB (Undefined Behavior) — 정의되지 않은 동작
비정상(illegal) 코드 구성이 실행될 때 발생하는 동작을 말해요. 정의되지 않은 동작에는 무작위·불규칙한 결과, 크래시, 결함(faulting) 등이 포함될 수 있어요. 버퍼 오버플로가 정의되지 않은 동작의 한 예예요.
UDA (User-Defined Attribute) — 사용자 정의 속성
컴파일 타임 리플렉션에 쓰도록 심볼에 붙이는 메타데이터를 말해요.
UFCS (Uniform Function Call Syntax) — 균일 함수 호출 구문
함수를 그 첫 번째 인자의 메서드인 것처럼 호출할 수 있는 능력을 말해요. 예를 들어 funct(arg)를 arg.funct()처럼 쓸 수 있죠.
더 알아보기 (Learn more)
- D 언어 공식 사양 전체: https://dlang.org/spec/spec.html
- 원문 용어 사전 페이지: https://dlang.org/spec/glossary.html