객체, 클래스, 인터페이스 유틸리티
객체, 클래스, 인터페이스 유틸리티 (Object, Class, and Interface Utilities)
객체 지향 프로그래밍을 하다 보면 "이 값이 객체인가?", "이 클래스가 저 인터페이스를 구현하는가?" 같은 질문이 필요한 경우가 많아요. object?, class?, interface? 같은 판별자부터, 클래스·인터페이스 정보를 조회하고 봉인(seal)하는 고급 함수까지, 이 절에서 객체 지향 관련 유틸리티들을 한자리에 모아서 살펴볼게요.
출처: Racket Reference
본문
procedure
(object? v) → boolean?
v : any/c
v가 객체면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (object? (new object%))
#t
> (object? object%)
#f
> (object? "clam chowder")
#f
procedure
(class? v) → boolean?
v : any/c
v가 클래스면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (class? object%)
#t
> (class? (class object% (super-new)))
#t
> (class? (new object%))
#f
> (class? "corn chowder")
#f
procedure
(interface? v) → boolean?
v : any/c
v가 인터페이스면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (interface? (interface () empty cons first rest))
#t
> (interface? object%)
#f
> (interface? "gazpacho")
#f
procedure
(generic? v) → boolean?
v : any/c
v가 generic이면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (define c%
(class object%
(super-new)
(define/public (m x)
(+ 3.14 x))))
> (generic? (generic c% m))
#t
> (generic? c%)
#f
> (generic? "borscht")
#f
procedure
(object=? a b) → boolean?
a : object?
b : object?
a와 b가 같은 new 호출에서 돌아왔는지 여부를 결정해요. 두 객체에 필드가 있으면, 이 프로시저는 한쪽 필드를 변형하면 다른 쪽의 그 필드도 바뀔지 결정해요.
이 프로시저는 정신적으로는 eq?와 비슷하지만 콘트랙트와도 올바르게 동작해요(그리고 더 강한 보장을 제공해요).
Examples:
> (define obj-1 (new object%))
> (define obj-2 (new object%))
> (define/contract obj-3 (object/c) obj-1)
> (object=? obj-1 obj-1)
#t
> (object=? obj-1 obj-2)
#f
> (object=? obj-1 obj-3)
#t
> (eq? obj-1 obj-1)
#t
> (eq? obj-1 obj-2)
#f
> (eq? obj-1 obj-3)
#f
procedure
(object-or-false=? a b) → boolean?
a : (or/c object? #f)
b : (or/c object? #f)
object=?와 같지만 두 인자에 대해 #f를 받아들이고, 두 인자가 모두 #f면 #t를 돌려줘요.
Examples:
> (object-or-false=? #f (new object%))
#f
> (object-or-false=? (new object%) #f)
#f
> (object-or-false=? #f #f)
#t
base 패키지의 6.1.1.8 버전에서 추가됐어요.
procedure
(object=-hash-code o) → fixnum?
o : object?
object=? 동등 관계에 해당하는 o의 해시 코드를 돌려줘요.
base 패키지의 7.1.0.6 버전에서 추가됐어요.
procedure
(object->vector object [opaque-v]) → vector?
object : object?
opaque-v : any/c = #f
object의 검사 가능한(inspectable) 필드들을 보여주는 벡터를 돌려줘요. struct->vector와 유사해요.
Examples:
> (object->vector (new (class object%
(super-new)
(field [x 5] [y 10]))))
'#(object:eval:119:0 ...)
procedure
(class->interface class) → interface?
class : class?
class가 암시적으로 정의하는 인터페이스를 돌려줘요.
Example:
> (class->interface object%)
#<interface:object%>
procedure
(object-interface object) → interface?
object : object?
object의 클래스가 암시적으로 정의하는 인터페이스를 돌려줘요.
Example:
> (object-interface (new object%))
#<interface:object%>
procedure
(is-a? v type) → boolean?
v : any/c
type : (or/c interface? class?)
v가 클래스 type의 인스턴스이거나, 인터페이스 type을 구현하는 클래스의 인스턴스면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (define 2d-point%
(class* object% (point<%>)
(super-new)
(field [x 0] [y 0])
(define/public (get-x) x)
(define/public (get-y) y)))
> (is-a? (new 2d-point%) 2d-point%)
#t
> (is-a? (new 2d-point%) point<%>)
#t
> (is-a? (new object%) 2d-point%)
#f
> (is-a? (new object%) point<%>)
#f
procedure
(subclass? v cls) → boolean?
v : any/c
cls : class?
v가 cls에서 파생된(또는 cls와 같은) 클래스면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (subclass? (class object% (super-new)) object%)
#t
> (subclass? object% (class object% (super-new)))
#f
> (subclass? object% object%)
#t
procedure
(implementation? v intf) → boolean?
v : any/c
intf : interface?
v가 intf를 구현하는 클래스면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (define c%
(class* object% (i<%>)
(super-new)
(define/public (go) 'go)))
> (implementation? c% i<%>)
#t
> (implementation? object% i<%>)
#f
procedure
(interface-extension? v intf) → boolean?
v : any/c
intf : interface?
v가 intf를 확장하는 인터페이스면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (define point<%> (interface () get-x get-y))
> (define colored-point<%> (interface (point<%>) color))
> (interface-extension? colored-point<%> point<%>)
#t
> (interface-extension? point<%> colored-point<%>)
#f
> (interface-extension? (interface () get-x get-y get-z) point<%>)
#f
procedure
(method-in-interface? sym intf) → boolean?
sym : symbol?
intf : interface?
intf(또는 그 조상 인터페이스 중 하나)의 멤버에 이름이 sym인 것이 있으면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (define i<%> (interface () get-x get-y))
> (method-in-interface? 'get-x i<%>)
#t
> (method-in-interface? 'get-z i<%>)
#f
procedure
(interface->method-names intf) → (listof symbol?)
intf : interface?
intf의 메서드 이름들을 담은 심볼 리스트를 돌려줘요. 슈퍼인터페이스에서 상속한 메서드를 포함하지만, 이름이 로컬인(즉 define-local-member-name으로 선언된) 메서드는 포함하지 않아요.
Examples:
> (define i<%> (interface () get-x get-y))
> (interface->method-names i<%>)
'(get-x get-y)
procedure
(object-method-arity-includes? object sym cnt) → boolean?
object : object?
sym : symbol?
cnt : exact-nonnegative-integer?
object가 cnt개의 인자를 받아들이는 sym이라는 이름의 메서드를 갖고 있으면 #t를, 그렇지 않으면 #f를 돌려줘요.
Examples:
> (define c%
(class object%
(super-new)
(define/public (m x [y 0])
(+ x y))))
> (object-method-arity-includes? (new c%) 'm 1)
#t
> (object-method-arity-includes? (new c%) 'm 2)
#t
> (object-method-arity-includes? (new c%) 'm 3)
#f
> (object-method-arity-includes? (new c%) 'n 1)
#f
procedure
(field-names object) → (listof symbol?)
object : object?
object에 바인딩된 모든 필드 이름의 리스트를 돌려줘요. 슈퍼인터페이스에서 상속한 필드를 포함하지만, 이름이 로컬인(즉 define-local-member-name으로 선언된) 필드는 포함하지 않아요.
Examples:
> (field-names (new object%))
'()
> (field-names (new (class object% (super-new) (field [x 0] [y 0]))))
'(x y)
procedure
(object-info object) → (or/c class? #f) boolean?
object : object?
struct-info의 반환 값과 유사한 두 값을 돌려줘요:
-
class: 클래스 또는
#f예요. 현재 inspector가 그 객체가 인스턴스인 어떤 클래스도 제어하지 않으면 결과는#f예요. -
skipped?: 첫 번째 결과가
object의 가장 구체적인 클래스에 해당하면#f를, 그렇지 않으면#t를 돌려줘요.
procedure
(class-info class)
→ symbol?
exact-nonnegative-integer?
(listof symbol?)
(any/c exact-nonnegative-integer? . -> . any/c)
(any/c exact-nonnegative-integer? any/c . -> . any/c)
(or/c class? #f)
boolean?
class : class?
struct-type-info의 반환 값과 유사한 일곱 값을 돌려줘요:
-
name: 클래스의 이름(심볼).
-
field-cnt: 클래스가 정의한 필드(공개·비공개)의 수.
-
field-name-list: 클래스의 공개 필드에 해당하는 심볼 리스트. 이 리스트는 상속된 필드를 포함하므로
field-cnt보다 클 수 있어요. -
field-accessor: 클래스의 인스턴스에서 필드 값을 얻는 접근자 프로시저. 접근자는 인스턴스와, 0(포함)과
field-cnt(제외) 사이의 필드 인덱스를 받아요. -
field-mutator: 클래스의 인스턴스에서 필드 값을 수정하는 변경자 프로시저. 변경자는 인스턴스, 0(포함)과
field-cnt(제외) 사이의 필드 인덱스, 새 필드 값을 받아요. -
super-class: 현재 inspector가 제어하는, 주어진 클래스의 가장 구체적인 조상에 대한 클래스. inspector가 제어하는 조상이 없으면
#f. -
skipped?: 여섯 번째 결과가 가장 구체적인 조상 클래스면
#f를, 그렇지 않으면#t를 돌려줘요.
struct
(struct exn:fail:object exn:fail ()
#:extra-constructor-name make-exn:fail:object)
클래스 관련 실패(예: 객체가 제공하지 않는 메서드를 호출하려는 시도)에 대해 발생해요.
procedure
(class-seal class key unsealed-inits unsealed-fields unsealed-methods
inst-proc member-proc) → class?
class : class?
key : symbol?
unsealed-inits : (listof symbol?)
unsealed-fields : (listof symbol?)
unsealed-methods : (listof symbol?)
inst-proc : (-> class? any)
member-proc : (-> class? (listof symbol?) any)
심볼 key로 키가 매겨진 봉인(seal)을 주어진 클래스에 추가해요. 주어진 unsealed-inits, unsealed-fields, unsealed-methods 리스트는 봉인에 영향을 받지 않는 해당 클래스 멤버를 나열해요.
클래스에 봉인이 있으면, 인스턴스화할 때 inst-proc 프로시저가 호출되고(보통 인스턴스화 시 오류를 일으키는 데 사용돼요), 서브클래스가 unsealed 리스트에 없는 클래스 멤버를 추가하려고 하면 member-proc 함수가 호출돼요(역시 보통 오류를 일으키는 데 사용돼요).
inst-proc는 인스턴스화가 시도된 클래스 값과 함께 호출돼요. member-proc는 클래스 값과 초기화 인자·필드·메서드 이름의 리스트와 함께 호출돼요.
procedure
(class-unseal class key wrong-key-proc) → class?
class : class?
key : symbol?
wrong-key-proc : (-> class? any)
class-seal 함수와 주어진 key로 이전에 봉인된 클래스의 봉인을 제거해요.
unseal이 클래스의 모든 봉인을 제거하면, 그 클래스 값은 자유롭게 인스턴스화되거나 서브클래싱될 수 있어요. 주어진 클래스 값에 봉인이 없거나 주어진 key로 된 봉인이 없으면 wrong-key-proc 함수가 클래스 값과 함께 호출돼요.
더 알아보기
- Classes and Objects — 클래스와 객체 전반.
- Object Equality and Hashing — 객체 동등성과 해싱.