DEFGENERIC — 제네릭 함수 정의하기

DEFGENERIC — 제네릭 함수 정의하기 (매크로)

generic function을 정의하거나 그 옵션·선언을 지정하는 매크로예요. 메서드가 어떤 인자 우선순위로 선택될지, method combination, 문서화 등을 선언적으로 지정하고, 메서드들을 정의하는 틀로도 쓰여요.

출처: DEFGENERIC - Common Lisp HyperSpec

시그니처 (Syntax)

defgeneric function-name gf-lambda-list [[option | {method-description}*]]
  => new-generic
option ::= (:argument-precedence-order parameter-name+) |
          (declare gf-declaration+) |
          (:documentation gf-documentation) |
          (:method-combination method-combination method-combination-argument*) |
          (:generic-function-class generic-function-class) |
          (:method-class method-class)

method-description ::= (:method method-qualifier* specialized-lambda-list [[declaration* | documentation]] form*)
  • function-namefunction name.
  • generic-function-classclass를 가리키는 non-nil symbol.
  • gf-declarationoptimize declaration specifier. 다른 declaration specifier는 허용되지 않아요.
  • gf-documentationstring. 평가되지 않아요.
  • gf-lambda-listgeneric function lambda list.
  • method-classclass를 가리키는 non-nil symbol.
  • method-combination-argumentobject.
  • method-combination-namemethod combination type를 가리키는 symbol.
  • method-qualifiers, specialized-lambda-list, declarations, documentation, formsdefmethod와 같아요.
  • new-genericgeneric function object.
  • parameter-namelambda-listrequired parameter를 가리키는 symbol. (:argument-precedence-order 옵션이 지정되면 lambda-list의 각 required parameterparameter-name으로 정확히 한 번 쓰여야 해요.)

본문 (Description)

매크로 defgenericgeneric function을 정의하거나, generic function 전체에 해당하는 옵션과 선언을 지정하는 데 쓰여요.

function-namelist이면 반드시 (setf symbol) 형태여야 해요. (fboundp function-name)false면 새 generic function이 생성돼요. (fdefinition function-name)generic function이면 그 generic function이 수정돼요. function-nameordinary function·macro·special operator를 가리키면 에러가 신호돼요.

defgeneric 매크로의 효과는 다음 세 단계를 수행한 것과 같아요. 첫째, 이전 defgeneric form이 정의한 method를 제거하고, 둘째, ensure-generic-function을 호출하며, 마지막으로 현재 defgeneric form이 지정한 methodgeneric function에 추가해요.

method-descriptiongeneric functionmethod를 정의해요. 각 methodlambda listgf-lambda-list 옵션이 지정한 lambda list와 일치해야 해요. method 설명이 전혀 지정되지 않고 같은 이름의 generic function이 아직 없으면, method가 없는 generic function이 생성돼요.

defgenericgf-lambda-list 인자는 이 generic functionmethod들에 대한 lambda list의 모양을 지정해요. 결과 generic function의 모든 method는 이 모양과 일치하는 lambda list를 가져야 해요. defgeneric form이 평가될 때 그 generic function의 일부 methodlambda listdefgeneric form에 주어진 것과 일치하지 않으면 에러가 신호돼요. method congruence에 대한 자세한 내용은 Section 7.6.4 (Congruent Lambda-lists for all Methods of a Generic Function)를 보세요.

generic function은 전달된 모든 인자 값만 method에 넘겨줘요. 기본값은 지원되지 않아요. 다만 method 정의의 optional·keyword 인자는 기본 초기값 form을 가질 수 있고 supplied-p 매개변수를 쓸 수 있다는 점에 유의하세요.

다음 옵션들이 제공돼요. 달리 명시되지 않는 한, 주어진 옵션은 한 번만 나타날 수 있어요.

:argument-precedence-order

특정 method를 선택할 때 generic function 호출의 필수 인자들이 특이성(specificity)에 대해 검사되는 순서를 지정해요. gf-lambda-list 인자에 지정된 각 필수 인자는 parameter-name으로 정확히 한 번 포함되어 완전하고 모호하지 않은 우선순위 순서가 제공되어야 해요. 이 조건이 맞지 않으면 에러가 신호돼요.

declare

generic function에 해당하는 선언을 지정하는 데 쓰여요.

optimize declaration specifier가 허용돼요. method 선택을 speed나 space 중 어느 쪽으로 최적화할지 지정하지만 method에는 효과가 없어요. method가 어떻게 최적화될지 제어하려면 optimize 선언을 defmethod form이나 method description에 직접 넣어야 해요. 표준이 요구하는 최적화 품질은 speed·space뿐이지만, 구현은 객체 시스템을 확장해 다른 품질을 인식할 수 있어요. method 선택 기법이 하나뿐이고 optimize declaration specifier를 무시하는 단순한 구현도 유효해요.

special, ftype, function, inline, notinline, declaration 선언은 허용되지 않아요. 개별 구현은 declare 옵션을 확장해 추가 선언을 지원할 수 있어요. 구현이 지원하지 않으면서 declaration proclamation에서 비표준 declaration identifier 이름으로 선언되지 않은 declaration specifier를 발견하면 경고를 내보내야 해요.

declare 옵션은 두 번 이상 지정될 수 있어요. 효과는 declaration specifier 목록들을 하나의 목록으로 이어 붙여 하나의 declare 옵션으로 지정한 것과 같아요.

:documentation

generic function object에 붙일 documentation string이고, function-name에는 function 종류로 붙어요.

:generic-function-class

generic function이 시스템이 제공하는 기본값(class standard-generic-function)과 다른 class를 갖도록 지정하는 데 쓰여요. class-name 인자는 generic functionclass가 될 수 있는 class의 이름이에요. function-name이 :generic-function-class 인자에 대해 다른 값을 가진 기존 generic function을 지정하고, 새 generic function class가 옛 것과 호환되면 change-class를 호출해 generic functionclass를 바꿔요. 그렇지 않으면 에러가 신호돼요.

:method-class

generic function의 모든 method가 시스템이 제공하는 기본값(class standard-method)과 다른 class를 갖도록 지정하는 데 쓰여요. class-name 인자는 methodclass가 될 수 있는 class의 이름이에요.

:method-combination

뒤에 method combination의 한 타입을 가리키는 symbol이 와요. 그 symbol 뒤에 오는 인자(있다면)는 method combination 타입에 따라 달라져요. 표준 method combination 타입은 어떤 인자도 지원하지 않는다는 점을 유의하세요. 다만 define-method-combination의 short form으로 정의된 모든 method combination 타입은 order라는 optional 인자를 받아들이며, 기본값은 :most-specific-first예요. :most-specific-last 값을 주면 보조 method의 순서에는 영향 없이 primary method의 순서를 뒤집어요.

method-description

method-description 인자는 generic function에 연관될 method를 정의해요. method description 안의 method-qualifierspecialized-lambda-list 인자는 defmethod와 같아요.

form 인자들은 method body를 지정해요. method의 body는 implicit block 안에 감싸져요. function-namesymbol이면 이 block은 generic function과 같은 이름을 가져요. function-name이 (setf symbol) 형태의 list이면 block의 이름은 symbol이에요.

구현은 defgeneric을 확장해 다른 옵션을 포함시킬 수 있어요. 로컬에서 구현되지 않은 옵션을 발견하면 구현이 에러를 신호하는 것이 요구돼요.

defgeneric은 컴파일 타임 부수효과를 수행할 의무가 없어요. 특히 method는 컴파일 중 호출되도록 설치되지 않아요. implementation은 컴파일 타임 에러 검사를 위해 generic function에 대한 정보를 저장할 수 있어요(호출 인자 수 검사나, 함수 이름의 정의가 보였다는 기록 같은 것).

예외 상황 (Exceptional Situations)

function-nameordinary function·macro·special operator를 가리키면 typeprogram-error인 에러가 신호돼요.

gf-lambda-list 인자에 지정된 각 필수 인자는 parameter-name으로 정확히 한 번 포함되어야 하며, 그렇지 않으면 typeprogram-error인 에러가 신호돼요.

method-description이 지정한 각 methodlambda listgf-lambda-list 옵션이 지정한 lambda list와 일치해야 하며, 그렇지 않으면 typeerror인 에러가 신호돼요.

defgeneric form이 평가될 때 그 generic function의 일부 methodlambda listdefgeneric form에 주어진 것과 일치하지 않으면 typeerror인 에러가 신호돼요.

주어진 option은 한 번만 나타날 수 있으며, 그렇지 않으면 typeprogram-error인 에러가 신호돼요.

function-name이 :generic-function-class 인자에 대해 다른 값을 가진 기존 generic function을 지정하고 새 generic function class가 옛 것과 호환되면 change-class를 호출해 class를 바꿔요. 그렇지 않으면 typeerror인 에러가 신호돼요.

구현은 defgeneric을 확장해 다른 옵션을 포함시킬 수 있어요. 로컬에서 구현되지 않은 옵션을 발견하면 구현이 typeprogram-error인 에러를 신호하는 것이 요구돼요.

더 알아보기 (See Also)

defmethod, documentation, ensure-generic-function, generic-function, Section 7.6.4 (Congruent Lambda-lists for all Methods of a Generic Function)

Notes

없음.