속성

속성 (Properties)

D에서는 모든 심볼(symbol), 타입(type), 표현식(expression)에 대해 조회할 수 있는 내장 속성(property)이 있어요. .init, .sizeof, .stringof, .mangleof 등과 같은 속성은 타입이나 표현식의 크기·기본값·이름·링키지 표현 등을 얻는 데 사용돼요. 이 문서는 공통 속성부터 타입별 속성, 사용자 정의 속성까지 다루어요.

출처: Properties

본문

공통 속성 (Common Properties)

모든 심볼, 타입, 표현식에는 조회할 수 있는 속성이 있어요:

속성 설명
.mangleof 타입의 'mangled' 표현을 나타내는 문자열
.stringof 타입의 소스 표현(source representation)을 나타내는 문자열

예제:

  • int.mangleof는 문자열 "i"를 산출해요.
  • int.stringof는 문자열 "int"를 산출해요.
  • (1+2).stringof는 문자열 "1 + 2"를 산출해요.

타입 속성 (Type Properties)

모든 타입은 조회할 수 있는 속성을 가져요. 모든 표현식도 이 속성들을 가지며, 이는 표현식의 타입 속성과 동일해요. 이 속성들은 다음과 같아요:

속성 설명
.init 초기화 값 (initializer)
.sizeof 바이트 단위 크기
.alignof 정렬 크기 (alignment size)

예제:

  • int.init0을 산출해요.
  • int.sizeof4를 산출해요.
  • (3).sizeof4를 산출해요 (3int이기 때문).

숫자 속성 (Numeric Properties)

정수형 (Integral Types) 속성:

속성 설명
.max 최대값
.min 최소값

예제:

  • byte.min-128을 산출해요.
  • ubyte.max255를 산출해요.

부동소수점형 (Floating Point Types) 속성:

속성 설명
.infinity 무한대 값
.nan NaN(Not a Number) 값 (다른 NaN 값도 생성될 수 있어요)
.dig 십진 정밀도 자릿수
.epsilon 값 1에 더해지는 가장 작은 증가분
.mant_dig 가수(mantissa)의 비트 수
.max_10_exp 10^max_10_exp가 표현 가능한 최대 int 값
.max_exp 2^(max_exp-1)이 표현 가능한 최대 int 값
.min_10_exp 10^min_10_exp가 정규화된 값으로 표현 가능한 최소 int 값
.min_exp 2^(min_exp-1)이 정규화된 값으로 표현 가능한 최소 int 값
.max 무한대가 아닌 가장 큰 표현 가능한 값
.min_normal 0이 아닌 가장 작은 표현 가능한 정규화된 값

예제:

  • float.nan은 부동소수점 NaN 값을 산출해요.
  • (2.5F).nan은 부동소수점 NaN 값을 산출해요.

복소 부동소수점형 (Complex Floating Point Types) 추가 속성:

속성 설명
.re 실수부 (real part)
.im 허수부 (imaginary part)

파생 타입 속성 (Derived Type Properties)

다음을 참고하세요:

.init 속성

.init는 기본 초기화 값(default initializer)인 상수 표현식을 산출해요. 타입에 적용하면 그 타입의 기본 초기화 값이고, 변수나 필드에 적용하면 그 변수나 필드 타입의 기본 초기화 값이에요. 각종 타입의 기본값은 아래와 같아요:

타입 .init
char '\xff'
dchar '\xffff'
wchar '\xffff'
Enum 첫 번째 멤버 값
정수 (Integers) 0
부동소수점 (Floating Point) NaN
참조 타입 (Reference Types) null
Struct 각 필드의 기본값
Union 첫 번째 멤버 값

Rationale: (근거) 가능하다면 타입의 기본값은 유효하지 않은 값(invalid value)이어야 해요.

int a;
int b = 1;

static assert(int.init == 0);
static assert(a.init == 0);
static assert(b.init == 0);

struct Foo
{
    int a;
    int b = 7;
}

static assert(Foo.init.a == 0);
static assert(Foo.init.b == 7);

.init vs 기본 초기화 (Default Initialization)

.init는 정적으로 초기화된 객체를 산출하는데, 이는 값 타입의 기본 초기화와 다를 수 있어요:

  1. 중첩 struct S의 경우, S.init의 컨텍스트 포인터는 null이에요.
  2. struct S@disable this();가 있으면 T.init가 논리적으로 올바르지 않은 객체를 반환할 수 있어요.

마찬가지로 struct의 정적 배열도 .init과 기본 초기화 사이에서 다른 동작을 보일 수 있어요.

.stringof 속성

.stringof는 자신의 접두부(prefix)의 소스 표현(source representation)인 상수 문자열을 산출해요. 타입에 적용하면 그 타입의 문자열이고, 표현식에 적용하면 그 표현식의 소스 표현이에요. 표현식은 평가되지 않아요.

module test;
import std.stdio;

struct Dog { }

enum Color { Red }

int i = 4;

void main()
{
    writeln((1+2).stringof);       // "1 + 2"
    writeln(test.stringof);        // "module test"
    writeln(Dog.stringof);         // "Dog"
    writeln(int.stringof);         // "int"
    writeln((int*[5][]).stringof); // "int*[5][]"
    writeln(Color.Red.stringof);   // "Red"
    writeln((5).stringof);         // "5"

    writeln((++i).stringof);       // "i += 1"
    assert(i == 4);                // `++i` was not evaluated
}

Implementation Defined: (구현 정의 사항) 타입이나 표현식의 문자열 표현은 달라질 수 있어요.

Best Practices: (모범 사례) 코드 생성을 위해 .stringof를 사용하지 마세요. 대신 identifier 특성(trait)이나 std.traits.fullyQualifiedName 같은 Phobos 헬퍼 함수를 사용하세요.

.sizeof 속성

e.sizeof는 표현식 e의 바이트 크기를 알려줘요. 멤버의 크기를 얻을 때는 this 객체가 필요하지 않아요:

struct S
{
    int a;
}

static assert(S.a.sizeof == 4);
static assert(Object.sizeof == (void*).sizeof);

.sizeof를 클래스 객체에 적용하면 클래스 인스턴스 크기가 아니라 클래스 참조의 크기를 반환해요. __traits(classInstanceSize)도 참고하세요.

.alignof 속성

.alignof는 표현식이나 타입의 정렬 크기(aligned size)를 알려줘요. 예를 들어 정렬 크기가 1이면 바이트 경계(byte boundary)에 정렬된다는 뜻이고, 4면 32비트 경계에 정렬된다는 뜻이에요. 예제는 align 속성을 참고하세요.

Implementation Defined: (구현 정의 사항) 실제 정렬 크기.

Best Practices: (모범 사례) 외부에서 정해진 레이아웃에 맞춰야 하는 객체를 배치할 때 특히 주의하세요. 데이터 정렬 불일치(data misalignment)는 특히 해로운 버그를 초래할 수 있어요. 올바른지 확인하는 assert를 넣을 가치가 있는 경우가 많아요.

.mangleof 속성

망글링(mangling)은 심볼이 생성된 객체 파일에서 텍스트 형태로 어떻게 표현되는지를 말해요. .mangleof는 적용된 타입이나 심볼의 표현에 대한 문자열 리터럴을 반환해요. D 링키지의 타입과 심볼 망글링은 Name Mangling에 정의돼 있어요.

Implementation Defined: (구현 정의 사항) 심볼에 선행 밑줄(_)이 추가되는지 여부, 그리고 non-D 링키지 타입·심볼의 망글링. C 및 C++ 링키지의 경우 이는 일반적으로 연관 C/C++ 컴파일러가 하는 것과 일치해요.

.classinfo 속성

.classinfo는 클래스 객체의 동적 타입(dynamic type)에 대한 정보를 제공해요. 타입 object.TypeInfo_Class에 대한 참조를 반환해요. .classinfo를 인터페이스에 적용하면 그 인터페이스의 정보를 제공하며, 인터페이스가 인스턴스일 수 있는 클래스의 정보는 주지 않아요.

.tupleof 속성

.tupleof는 struct나 class의 모든 비정적(non-static) 필드의 심볼 시퀀스를 제공해요. 튜플 안의 필드 순서는 필드가 선언된 순서와 일치해요.

클래스의 경우 숨겨진 필드와 기반 클래스의 필드는 제외돼요.

흔한 사용 사례는 foreach 루프로 필드를 순회하는 것이에요:

struct Vector3
{
    int x, y, z;
}

void test()
{
    Vector3 v = Vector3(5, 10, 15);
    float sum = 0;
    foreach(num; v.tupleof)
    {
        sum+= num;
    }
    writeln(sum); //30
}

사용자 정의 속성 (User-Defined Properties)

사용자 정의 속성은 Property Functions를 사용해 만들 수 있어요.

더 알아보기