타입 호환성 — 제네릭 특수화 결과는 언제 호환될까
타입 호환성 — 제네릭 특수화 결과는 언제 호환될까
제네릭 클래스를 특수화하면 그 결과는 새로운 독립된 타입이 돼요. 그런데 특수화에 사용한 템플릿 타입이 같으면 이 타입들은 대입 호환(assignment compatible)이 돼요.
본문
다음과 같은 제네릭 정의가 있다고 해볼게요.
{$mode objfpc}
unit ua;
interface
type
Generic TMyClass<T> = Class(TObject)
Procedure DoSomething(A : T; B : INteger);
end;
Implementation
Procedure TMyClass.DoSomething(A : T; B : Integer);
begin
// Some code.
end;
end.
여기에 두 개의 특수화가 있다고 해요.
{$mode objfpc}
unit ub;
interface
uses ua;
Type
TB = Specialize TMyClass<string>;
implementation
end.
그리고 다음은 동일한 특수화지만 다른 유닛에 있다고 해요.
{$mode objfpc}
unit uc;
interface
uses ua;
Type
TB = Specialize TMyClass<string>;
implementation
end.
그러면 아래 코드는 컴파일돼요.
{$mode objfpc}
unit ud;
interface
uses ua,ub,uc;
Var
B : ub.TB;
C : uc.TB;
implementation
begin
B:=C;
end.
여기서 ub.TB와 uc.TB는 대입 호환이에요. 타입이 서로 다른 유닛에 정의돼 있든 같은 유닛에 정의돼 있든 상관없어요. 같은 유닛에 정의해도 마찬가지예요.
{$mode objfpc}
unit ue;
interface
uses ua;
Type
TB = Specialize TMyClass<string>;
TC = Specialize TMyClass<string>;
Var
B : TB;
C : TC;
implementation
begin
B:=C;
end.
같은 타입을 파라미터로 특수화한 제네릭 클래스는 매번 새로운 독립 타입이지만, 특수화에 쓴 템플릿 타입이 같으면 이 타입들은 대입 호환이 돼요.
만약 다른 템플릿 타입으로 특수화했다면 타입은 여전히 구별되지만 더 이상 대입 호환이 아니에요. 즉 아래 코드는 컴파일되지 않아요.
{$mode objfpc}
unit uf;
interface
uses ua;
Type
TB = Specialize TMyClass<string>;
TC = Specialize TMyClass<integer>;
Var
B : TB;
C : TC;
implementation
begin
B:=C;
end.
컴파일하면 다음과 같은 오류가 나요.
Error: Incompatible types: got "TMyClass<System.LongInt>"
expected "TMyClass<System.ShortString>"
한 가지 기억해 둘 점은, string과 integer가 서로 다른 템플릿 타입이므로 특수화 결과도 서로 다른 타입이 된다는 거예요. 같은 타입 파라미터로 특수화한 경우에만 대입 호환이 성립해요.
더 알아보기
- 제네릭의 타입 제한과 다른 타입 사용 규칙은 A word about scope에서 계속돼요
- 제네릭에서 변수의 초기화는 Using the default intrinsic을 참고하세요