타입 호환성 — 제네릭 특수화 결과는 언제 호환될까

타입 호환성 — 제네릭 특수화 결과는 언제 호환될까

제네릭 클래스를 특수화하면 그 결과는 새로운 독립된 타입이 돼요. 그런데 특수화에 사용한 템플릿 타입이 같으면 이 타입들은 대입 호환(assignment compatible)이 돼요.

출처: Type compatibility — Free Pascal Reference

본문

다음과 같은 제네릭 정의가 있다고 해볼게요.

{$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.TBuc.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>"

한 가지 기억해 둘 점은, stringinteger가 서로 다른 템플릿 타입이므로 특수화 결과도 서로 다른 타입이 된다는 거예요. 같은 타입 파라미터로 특수화한 경우에만 대입 호환이 성립해요.

더 알아보기