WITH-ACCESSORS — CLOS 슬롯을 지역 변수처럼 쓰는 매크로

WITH-ACCESSORS — CLOS 슬롯을 지역 변수처럼 쓰는 매크로

CLOS 객체의 슬롯을 접근자(accessor)를 통해 읽고 쓰는 일을 반복하다 보면 코드가 길어지기 쉬워요. with-accessors는 슬롯을 지역 변수처럼 이름으로 접근할 수 있게 해서 그 반복을 줄여줘요.

출처: CLHS: Macro WITH-ACCESSORS

이 문서는 CLOS(객체지향) 관련 매크로입니다. 슬롯 접근을 편하게 하는 데 주로 유용해요.

시그니처

with-accessors ({slot-entry}*) instance-form declaration* form* => results*

slot-entry::= (variable-name accessor-name)

본문

인자와 값 (Arguments and Values)

  • variable-name — 변수 이름(variable name); 평가되지 않아요.
  • accessor-name — 함수 이름(function name); 평가되지 않아요.
  • instance-form — 폼; 평가돼요.
  • declarationdeclare 식; 평가되지 않아요.
  • forms — 암묵적 progn.
  • resultsforms가 돌려준 값.

설명 (Description)

slot-entry로 지정된 슬롯들을 마치 변수인 것처럼 접근자를 통해 어휘적으로 쓸 수 있는 어휘 환경을 만들어요. with-accessorsslot-entry로 지정된 슬롯에 접근하기 위해 적절한 접근자들을 호출해요. setfsetq 둘 다 슬롯 값을 설정하는 데 쓸 수 있어요.

예제 (Examples)

 (defclass thing ()
           ((x :initarg :x :accessor thing-x)
            (y :initarg :y :accessor thing-y)))
=>  #<STANDARD-CLASS THING 250020173>
 (defmethod (setf thing-x) :before (new-x (thing thing))
   (format t "~&Changing X from ~D to ~D in ~S.~%"
           (thing-x thing) new-x thing))
 (setq thing1 (make-instance 'thing :x 1 :y 2)) =>  #<THING 43135676>
 (setq thing2 (make-instance 'thing :x 7 :y 8)) =>  #<THING 43147374>
 (with-accessors ((x1 thing-x) (y1 thing-y))
                 thing1
   (with-accessors ((x2 thing-x) (y2 thing-y))
                   thing2
     (list (list x1 (thing-x thing1) y1 (thing-y thing1)
                 x2 (thing-x thing2) y2 (thing-y thing2))
           (setq x1 (+ y1 x2))
           (list x1 (thing-x thing1) y1 (thing-y thing1)
                 x2 (thing-x thing2) y2 (thing-y thing2))
           (setf (thing-x thing2) (list x1))
           (list x1 (thing-x thing1) y1 (thing-y thing1)
                 x2 (thing-x thing2) y2 (thing-y thing2)))))
>>  Changing X from 1 to 9 in #<THING 43135676>.
>>  Changing X from 7 to (9) in #<THING 43147374>.
=>  ((1 1 2 2 7 7 8 8)
     9
     (9 9 2 2 7 7 8 8)
     (9)
     (9 9 2 2 (9) (9) 8 8))

예제에서 x1, y1처럼 보이는 이름이 실제로는 thing-x, thing-y 접근자를 통해 슬롯을 읽고 쓰는 걸 확인할 수 있어요.

영향 (Affected By)

defclass.

특이 상황 (Exceptional Situations)

어떤 accessor-name이 그 인스턴스의 접근자 이름이 아니면 결과는 정의되지 않아요(undefined).

참고 (Notes)

다음 형태의 with-accessors 식은:

(with-accessors (slot-entry1 ... slot-entryn) instance-form form1 ... formk)

이것과 동등하게 확장돼요:

(let ((in instance-form))
  (symbol-macrolet (Q1 ... Qn) form1 ... formk))

여기서 Qi는 이래요:

 (variable-namei () (accessor-namei in))

더 알아보기

  • with-slots — 슬롯을 직접 이름으로 접근하는 매크로
  • symbol-macrolet — 심볼 매크로 설치 매크로