TheArtandScienceofSmalltalk:Chapter 06

From 흡혈양파의 번역工房
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
제 6 장 스몰토크 클래스 라이브러리

스몰토크 클래스 라이브러리

스몰토크 언어를 설명하면서 스몰토크 개발 환경에 대해서도 간략하게 설명했으니 이제 나머지 부분인 스몰토크 클래스 라이브러리를 살펴봄으로써 그림을 완성할 수 있겠다. 표준 VisualWorks 이미지에는 1300개가 넘는 클래스가 존재한다-추가로 보관하거나 다른 사람의 클래스를 사용하려는 경우는 훨씬 더 많을 것이다. 스몰토크 프로그램을 작성할 때는 이러한 클래스의 재사용을 피할 수가 없으며, 많은 면에서 볼 때 재사용을 많이 할수록 좋다. 하지만 클래스 모두를 상세하게 문서화하기엔 수천 페이지가 필요할 것이다. 다행히도 그럴 필요가 없다.


클래스 라이브러리에서 시스템이 작동하게 만드는 클래스의 비율은 적절한 편이며 ('스몰토크는 스몰토크로 작성되기 때문에'), 당신이 직접 재사용하도록 만들어진 것이 아니다. 그럼에도 불구하고 당신에게 노출된 복잡성을 이해할 필요가 없다는 사실을 기억하는 한 이러한 클래스에 대한 지식을 갖고 있다면 여전히 흥미로울 것이다!


나머지 클래스들 중에서 사용 빈도수가 높아 풍부한 지식을 갖게 될 클래스는 소수에 불과한데, 대부분은 생각 없이 사용하기 때문이다 (문자열, 부울, 컬렉션, 기타 공통적 객체들이 이 카테고리에 속한다).


하지만 일반적으로는 시스템 내 클래스를 직접 사용하기 전에는 클래스에 대해 아는 바가 거의 없다는 사실을 발견할 것이다. 그 때는 브라우저 툴을 잘 사용하고 자신이 찾는 일반적인 기능을 훌륭하게 이해한다면 매뉴얼을 뒤지지 않고도 자신이 찾는 유형의 기능을 찾을 수 있다.


이번 장의 목표는 스몰토크 클래스 라이브러리에 관한 지침을 제공하고, 그 지침을 어떻게 읽는지 교육하는 데에 있다. 클래스 라이브러리를 전체적으로 살펴보면서 당신이 후에 다시 살펴볼법한 중요한 클래스는 모두 설명하고자 한다. 클래스 라이브러리에는 훌륭한 스몰토크 '스타일'을 보여주는 예가 많이 포함되어 있음을 발견할 것이다. 후에 실린 장들은 이러한 클래스들 중 일부를 더 상세히 설명한다. 우선은 그 동안 만나게 될 공통적 클래스를 살펴볼 필요가 있겠다.


표준 프로토콜

앞장에서는 스몰토크 개발 환경이 각 클래스 내 메서드를 프로토콜이라 불리는 그룹으로 분리한다고 언급한 바 있다. 이는 무작위 분할이 아니라 메서드가 실행되는 목적을 반영하여 분할된다. 이러한 그룹화는 프로그래머를 돕기 위함이며, 어떤 식으로든 시스템의 기능에는 영향을 미치지 않는다는 사실을 기억하라.


프로토콜의 존재로 인해 도움을 받는 프로그래머들은 두 가지 부류로 나뉜다. 우선 클래스의 원 작성자들이 있다-그리고 물론 당신이 클래스를 작성했다면 당신도 이 부류에 속할 것이다. 하지만 클래스의 재사용자들도 있다. 표준 스몰토크 라이브러리의 클래스라면 두 번째 부류에 속할 것이다. 즉, 프로토콜명은 내부에 있는 메서드의 목적과 기능을 알려주는 중요한 단서를 형성함을 의미한다.


물론 서로 다른 기능을 수행하긴 하나 많은 스몰토크 클래스는 개념적으로 비슷한 메서드를 가진다. 지난 수년간 스몰토크 프로그래머들은 이러한 메서드들을 포함하는 프로토콜명을 몇 가지 개발해왔다. 이러한 프로토콜을 이해함으로써 (그리고 자신만의 클래스를 작성할 때 그 규칙을 따름으로써) 특정 클래스의 기능을 훨씬 더 쉽게 이해할 수 있게 된다.


클래스 라이브러리를 살펴보기 전에 표준 프로토콜 몇 가지만 훑어보겠다. 이는 가장 공통적인 프로토콜로서, 프로토콜명이 어떻게 내부 메서드 타입과 연관되는지 설명한다.


initialize-release

이 프로토콜은 클래스의 새 인스턴스를 초기화하고, (빈도가 낮긴 하지만) 해제하는 (수명이 끝날 때 정리하는) 것과 관련된 메서드를 포함한다. 객체를 초기화하는 메서드에 자주 사용되는 이름은 initialize이고, 후에 정리하는 메서드에 흔히 사용되는 이름은 release이다.


accessing

이 중요한 프로토콜은 주로 객체의 private 인스턴스 변수로 접근을 제공하는 메서드를 포함한다. 앞장 마지막에 실린 클래스 정의 예제를 실행했다면 이러한 유형의 메서드를 벌써 생성했을 것이다.


accessing 메서드의 유형에는 두 가지가 있다. 인스턴스 변수의 값을 리턴하는 'get' 메서드가 있고, 인스턴스 변수의 값을 특정 객체로 설정하도록 해주는 'set' 메서드가 있다. 규칙상 'get' 메서드는 단순히 그것이 리턴하는 인스턴스 변수와 동일하게 명명되는 반면 'set' 메서드는 콜론(trailing colon, :)과 동일한 이름을 갖고 물론 단일 매개변수를 취한다. 클래스 내 'get'과 'set' 메서드의 존재를 통해 클래스의 작성자가 그 클래스의 인스턴스의 인스턴스 변수로 당신이 접근하도록 의도했는지 여부를 유추할 수 있다.


testing

testing 프로토콜은 객체의 특성을 요청 시 (예: isEven에게 integer를 요청 시, 또는 isHil에게 어떤 객체를 요청 시) true 와 false 중 하나를 리턴하는 메서드를 포함한다.


comparing

comparing 프로토콜은 testing과 유사한 메서드를 포함하지만 true 또는 false를 리턴하기 전에 객체를 비교하는 매개변수를 취한다는 점이 다르다. 예를 들어, colour1 isMoreBlueThan: colour2와 같은 표현식이 true 또는 false를 리턴한다고 가정하자. isMoreBlueThan: 메서드는 마땅히 comparing이라는 프로토콜에 속할 것이다.


displaying

이 프로토콜은 특히 스몰토크의 그래픽 사용자 인터페이스를 구현하는 클래스에 적용된다. 이는 화면에 사실상 객체를 그리는 메서드를 포함하는데, 특히 중요한 메서드로 displayOn:을 들 수 있다. 화면에 표시하는 것과 관련된 대부분의 클래스는 이 프로토콜을 가질 것이다. 화면에 표시되는 방식을 변경하거나 이해하려면 이 프로토콜을 먼저 살펴보아야 한다.


printing

많은 기본적인 클래스들이 printing 프로토콜을 갖고 있다. 이는 객체의 표현을 인쇄된 형태로 생성하는 메서드를 포함한다. 시스템 내 각 객체가 어떻게 이러한 기능을 갖는지 간략하게 살펴볼 것이다.


updating

이 프로토콜은 다른 객체들의 변경내용에 관한 통지를 수신하는 것과 관련된 특수 메서드 집합을 항상 포함한다. 이러한 메서드들은 제 8장, 의존성 메커니즘에서 설명한다.


private

private 프로토콜은 클래스 작성자가 사용을 제한한 메서드를 포함한다. 이는 시스템이 강요하는 것이 아니라 규칙의 문제다. 종종 private 메서드들은 그것이 정의된 클래스 외부에서 사용되지 못하도록 되어 있다. 즉, 동일한 클래스 내에서 다른 메서드들에 의해 호출되도록 만들어졌다. 때로는 서브클래스가 사용하기도 하며, 밀접하게 결합된 클래스의 그룹들 간 사용되기도 할 것이다. 의도가 무엇이든, private 메서드를 사용할 수 있다면 메서드가 private로 간주되어 있으니 시스템의 배포(release)에 따라 특히 변경되기 쉽다는 사실을 주의해야 한다. 분명히 경고하는 바이다!


instance-creation

일부 클래스 내 '클래스측'에서 발견하게 될 프로토콜이다 (브라우저에서 class 버튼을 누름으로써). 이 프로토콜은 클래스가 이해하는 메서드와, 클래스의 새 인스턴스를 만들어 리턴하는 메서드를 포함한다. 주로 이러한 메서드들은 특정 클래스에 적절한 방식으로 특수화될 것이다. 따라서 사용하고 싶은 클래스를 찾으면 여기서 그 인스턴스를 만드는 방법을 찾기 좋다. 하지만 클래스가 instance-creation 프로토콜을 갖고 있지 않다고 해서 인스턴스를 만들 수 없다는 뜻은 아니다. 클래스가 그 슈퍼클래스로부터 상속되는 메서드를 사용할 가능성도 있다. 클래스 계층구조 브라우저를 열어 트리의 상향으로 instance-creation 프로토콜을 가진 클래스를 찾을 수 있을 것이다.


클래스 라이브러리 살펴보기

이제 스몰토크 클래스 계층구조를 살펴볼 때가 되었다. 클래스 계층구조는 사실상 최종 슈퍼클래스 Object 밑에서 뻗어나가는 트리에 해당한다. 하지만 계층구조 트리를 따라감으로써 클래스 라이브러리를 살펴보는 대신 개발 환경에서 클래스를 카테고리로 분류하는 방식을 이용해 시스템 브라우저에 표시되는 순서대로 살펴볼 것이다.


원한다면 우리가 논하는 동안 시스템 브라우저를 이용해 클래스를 보는 방법을 따라해볼 수 있겠다. 시스템 브라우저의 클래스 페인 (좌측 두 번째) 아래 팝업 메뉴에서 hierarchy, definition, comment 명령을 자유롭게 사용하여 클래스의 목적과 클래스가 서로 어떻게 연관되는지를 이해하는 데 도움이 되도록 한다. 관심이 있는 대상이 있다면 직감대로 행동하길 바란다.


살펴보게 될 클래스가 중요하거나 자주 사용되는 경우 상세히 설명할 것이다. 자주 사용되지 않는 곳에서는 간단히 클래스가 있다는 것만 언급할 것이다. 추후 언젠가 이러한 클래스를 사용할 필요가 있는 경우 매뉴얼을 읽거나 스스로 살펴볼 수 있겠다. 이제 시작하자...


Magnitude-General

첫 번째 카테고리는 'magnitude'를 가진 대상들의 표현과 관련된 클래스를 포함한다. 계층구조에서 이 부분에 해당하는 기반 클래스(root class)가 Magnitude인데, 이는 단순히 비교하는 방법을 정의한다 (<, >= 등). Magnitude는 Object로부터 상속된다. 비교 연산자(comparisons)는 다른 대상과 관련해 정의된다. 이 클래스가 일부 메서드를 정의하되 실제로 작동하는 방식이 알려졌을 때는 클래스 계층구조의 하층에서 구현되도록 남겨둔다는 사실을 주목하라. 실제로 이러한 메서드 구현의 지연은 주로 self subclassResponsibility 메시지 표현식을 이용해 선언된다. 일자와 시간 개념을 나타내는 것과 관련된 클래스 또한 이 카테고리에서 정의됨을 주의한다.


Magnitude-Numbers

여기서는 좀 더 구체적으로 들어간다. Magnitude-Numbers는 시스템이 숫자를 표현하는 데 사용하는 모든 클래스를 포함한다. 이를 살펴봄으로써 스몰토크가 숫자를 처리하는 형태들을 발견하고, 숫자 객체에 실행할 수 있는 연산들을 모두 살펴볼 수 있다.


ArithmeticValue는 이 계층구조의 추상적 (인스턴스가 없음) 슈퍼클래스에 해당한다. 이는 모든 숫자가 실행할 수 있는 모든 기본 연산을 포함한다. 이 클래스의 서브클래스는 (특히 Number) 특정 유형의 숫자에 적절한 연산을 추가한다. 스몰토크 언어의 일부로 생각해왔을 산술 연산이 (+, -, *, /, ...) 사실은 클래스 계층구조의 일부로 정의됨을 주목한다. 수학 함수와 반올림(rounding) 연산도 있다. 마지막으로 Integer 내에는 timesRepeat: 이라는 메서드가 있는데, 이 메서드를 integer로 전송 시 매개변수로서 전달된 블록을 적절한 수만큼 반복한다. 예를 들어:

3 timesRepeat: [Transcript show: 'Hello!' ; space].


스몰토크의 중요한 기능으로 보일 수도 있으나 다른 제어 구조의 힘을 보면 (특히 다음 장에서 살펴볼 컬렉션 열거) 실제로 극히 드물게 사용됨을 알 수 있다.


Collections-Abstract

해당 카테고리와 그에 따른 Collections- 카테고리들은 모두 collection 클래스를 포함한다. 이 클래스들의 인스턴스들은 다른 객체들의 컬렉션을 보유한다. 이는 중요하고 재사용 빈도가 높은 클래스기 때문에 제 7장, 컬렉션 클래스에서 집중적으로 다룬다. 따라서 내용은 제 7장에서 상세히 논하겠다.


Graphics-Geometry

Graphics-Geometry는 형상 요소(geometric entity)를 표현해야 하는 임무를 가진 클래스를 모두 포함한다. 그 중에서 Point와 Rectangle이 중요하다. Point의 (사실 ArithmetricValue의 서브클래스로, 카테고리를 이용해 상속이 아니라 함수를 어떻게 설명하는지 증명한다) 인스턴스들은 point의 개념을 2차원 좌표 공간에 표현한다. 사용자 인터페이스를 구현하는 모든 클래스에 중요하다. Rectangle의 인스턴스들은 직사각형 영영을 표현하고 (사실상 두 개의 point를 보유함으로써), 사용자 인터페이스 클래스에 매우 중요하다.


Graphics- 카테고리의 나머지는 시스템이 처리해야 하는 모든 그래픽적 개념을 표현하는 클래스를 포함한다. 여기에는 폰트, 색상, 팔레트, 이미지, 텍스트 등이 포함된다. 실제 GUI 클래스 대부분은 (윈도우, 위젯 등) 이 카테고리에 속하지 않는다는 사실을 주목한다.


Kernel-Objects

클래스 라이브러리의 핵심으로 도달하고 있다. Kernel-Objects는 전체 시스템에서 아마도 가장 중요한 클래스인 object를 포함한다. 이 클래스는 스몰토크 클래스 계층구조의 루트(root)로서 풍부한 기능을 제공하므로 잠시 멈춰 상세히 살펴보겠다.


Object – 계층구조의 루트

앞서 관찰했듯이 시스템 내 모든 단일 클래스는 궁극적으로 object로부터 상속된다. 즉, 시스템 내 모든 단일 객체는 (인스턴스 그리고 클래스) Object에서 정의된 메시지를 이해하고 그에 응답할 것이다. Object의 다양한 프로토콜에서 찾게 될 순서대로 기능을 몇 가지 살펴보고자 한다:


initialize-release 프로토콜에서 release 메서드는 객체가 파괴되기 전에 가질 수 있는 모든 종속자를 해제한다 (제 8장, 의존성 메커니즘 참고). Object에서 정의된 initialize 메서드가 없다는 사실을 주목한다. 즉, initialize를 만일 클래스 계층구조 어디서든 이 메서드를 정의하지 않는 객체로 전송할 경우 오류가 발생할 것을 의미한다.


accessing에는 데이터를 컬렉션으로 보관하는 서브클래스에 대해 기반(foundations)을 제공하는 다수의 메서드가 있다. 이 프로토콜에서 직접 사용할 법한 유일한 메서드는 yourself이다. 이 메서드는 self를 리턴하는데, 처음엔 무의미하다고 생각할지도 모르겠다. 드물긴 하지만 이것이 유용하게 사용되는 경우가 있다. 예제를 확인하려면 yourself의 송신자를 살펴보라 (브라우저에서 senders 명령을 이용).


testing에는 Object 클래스가 그 인스턴스가 아닌 것들을 모두 정의한다 (nil, integer, string 등). 따라서 이러한 메시지는 false 대신 true를 리턴하도록 적절한 서브클래스에서 오버라이드될 수 있다.


comparing에서는 스몰토크에서 매우 중요한 두 가지 비교 연산자, =와 ==의 정의를 볼 수 있다. 두 가지 비교 연산자의 차이를 꼭 이해할 필요가 있다. = 연산자는 두 개의 객체가 '동등(equal)'한지 검사한다. 이는 객체의 클래스에 따라 좌우되며, =의 구현자(implementor)를 살펴보면 많은 클래스들이 그것을 적절한 방식으로 재정의하고 있음을 발견할 것이다 (예: 두 개의 Rectangle 인스턴스 좌표가 동일할 경우 둘 다 =가 될 수 있다).


반면 == 연산자는 메시지의 수신자와 매개변수가 '등가적(equivalent)'인지 검사한다. 다시 말해, 둘이 동일한 객체를 참조하는지를 검사한다는 의미다. 예를 들어, rect1=rect2 표현식은 recti와 rect2가 그저 동일한 좌표로 된 두 개의 rectangles를 포함하는지 여부가 아니라 동일한 Rectangle 인스턴스를 포함하는 두 개의 변수일 경우에만 true를 리턴할 것이다. 따라서 =보다 훨씬 더 강력한 검사에 해당한다.


comparing 프로토콜은 객체의 해시 코딩(hash-coding)을 위한 메서드들도 포함한다. 이는 특정 종류의 컬렉션에 보관될 때 객체의 효율적인 검색을 제공하는 데 사용된다.


Copying 프로토콜은 객체의 복사본을 생성하기 위한 메서드들을 포함한다. 스몰토크는 deepCopy와 (객체와 그 모든 인스턴스 변수들이 재귀적으로 복사된다) shallowCopy를 (객체가 복사되지만 복사본의 인스턴스 변수들은 모두 원본과 동일한 객체를 가리킨다) 구별하는 데 사용된다. 하지만 deepCopy는 기본적으로 결함이 있는 개념으로 밝혀졌기 때문에 현재는 shallowCopy가 지원된다.


Converting 프로토콜은 수신자를 그 인스턴스 변수들 중 하나로서 포함하는 다른 객체들을 생성하는 데 사용되는 두 개의 메서드를 포함한다 (->와 asValue). 자주 필요한 것으로 밝혀져 편의상 이곳에 포함시켰다.


dependents access, updating, changing, dependents collection 프로토콜들은 제 8장에서 살펴볼 의존성 메커니즘을 구현하는 데 사용되는 메서드를 포함한다. 이에 해당하는 메서드들은 제 8장에서 상세히 설명하겠다.


printing 프로토콜은 시스템 내 모든 객체가 앞서 살펴본 인쇄된 표현(printed representation)을 가질 수 있도록 해주는 메서드들을 포함한다. 개발 환경을 이용해 객체를 인쇄할 때 눈치챘겠지만 무의미한 내부 포인터(예: 7af4ld25) 대신 항시 유용하게 스스로를 설명한다 (예: aPopUpMenu). 이를 책임지는 메서드는 printOn: 로, 시스템이 객체의 인쇄된 표현을 필요로 할 때마다 호출된다. Object 내 기본 정의는 단순히 객체 클래스의 이름을 이용하되 앞에 'a' 또는 'an'을 붙인다. Object의 많은 서브클래스들은 실제로 개별적 객체를 설명하는 훨씬 더 유용한 문자열을 생성한다 (예: x 좌표가 3, y 좌표가 4인 Point는 단순히 aPoint가 아니라 3@4를 인쇄할 것이다). 자신의 객체가 좀 더 설명적으로 인쇄되길 원한다면 자신의 클래스에 printOn:을 재정의할 수도 있다. 예를 확인하려면 이의 다른 구현자를 살펴보라.


printing 프로토콜은 storeString 라는 메서드도 포함한다. 해당 메서드는 스몰토크 코드 조각을 형성하는 문자 시퀀스를 생성한다. 이를 실행하면 해당 코드는 storeString 메시지가 전송된 객체와 정확히 동일한 객체를 생성할 것이다. 이런 놀라운 기능은 객체를 순차적 형태로 표현하는 데 기본이 된다.


다음 프로토콜, class membership은 객체가 어떤 클래스의 인스턴스인지를 시험하는 기능 집합을 제공한다. 특히 isMemberOf: 와 (특정 클래스의 인스턴스) isKindOf:의 (특정 클래스 또는 그 서브클래스들 중 하나의 인스턴스) 차이를 주목하라.


handling protocol 메시지는 몇몇 중요한 메서드를 포함하는데, 그 중 perform: 이 가장 간단하다. 해당 메서드들은 제 10장, 플러그인 가능성과 어댑터에서 살펴볼 것이다.


error handling 프로토콜은 halt 와 같은 몇 가지 유용한 메서드를 포함한다. 평가 시 현재 메서드의 실행을 중단시키고 알림창(notifier window)을 연다. 이는 self halt 표현식에 단순히 디버깅 이유를 넣음으로써 자신의 코드에 중단점(breakpoint)을 삽입할 수 있음을 의미한다. 프로토콜은 doesNotunderstand: 도 포함한다. 이 메시지는 실행되어야 하는 메시지를 이해하지 못하는 객체로 전송된다. 보통은 알림창을 열지만 원할 경우 오버라이드하여 더 나은 일을 수행할 수도 있다.


마지막으로 이 프로토콜에서 shouldNotImplement 와 subclassResponsibilty 메시지는 서브클래스가 슈퍼클래스에서 정의된 메서드를 '정의해제'하길 원할 때를 나타내거나, 서브클래스가 슈퍼클래스에서 정의된 메서드를 구현해야 함을 나타낼 때 사용 가능하다.


user interface 프로토콜은 어떤 객체든 inspect(검사)하거나 그 클래스를 browse(살펴볼) 할 수 있도록 해주는 메서드들을 제공한다. Inspect 또는 browse를 어떤 객체로든 전송하기만 하면 적절한 툴이 열릴 것이다.


Object에서 나머지 프로토콜들은 프로그래머가 직접 사용할 가능성이 적거나 내부적으로 사용되는 메서드들을 포함한다. 하지만 시스템이 어떻게 작용하는지 더 잘 이해하고 싶다면 언제든 살펴보도록 한다.


클래스 라이브러리 살펴보기 (계속)

가장 중요한 클래스인 Object를 자세히 살펴보았으니 이제 잠시 중단했던 스몰토크 클래스 라이브러리에 대한 탐구를 계속해보겠다.

Kernel-Objects

Object 외에도 이 카테고리는 시스템의 기능에 필수적이면서 매우 흔히 사용되는 클래스들을 포함한다. 특히 Boolean, True, False 클래스들은 모두 스몰토크에서 논리적 연산과 관련된 기능이다. Boolean 클래스는 모든 연산을 정의하지만 실제로 그 서브클래스-True와 False-에서 구현된다. 이 서브클래스 각각은 true와 false라는 단일 인스턴스를 갖는다. Boolean을 살펴보면 스몰토크가 지원하는 모든 유형의 논리적 연산과 (&, ㅣ, not 등), 당신이 사용할 수 있는 유형의 제어 구조가 (ifFalse:, ifTrue: 등) 표시될 것이다.


언어에 속한다고 생각했을 법한 것들이 (예: 산술) 어떻게 사실은 클래스 라이브러리에 해당하는지를 다시 주목해보자. 예를 들어, 조건문은 블록을 매개변수로 취하는 객체로 ifTrue: 메시지를 전송함으로써 구현된다. 블록은 객체가 True 클래스의 인스턴스인 경우에만 실행되고, False 클래스의 인스턴스인 경우에는 실행되지 않는다. 다음을 예로 들어보겠다:

27 > (3+4) ifTrue:  [Transcript show: 'Bigger!'].


True와 False 클래스에 있는 ifTrue: 의 구현부에서 이것이 어떻게 작용하는지를 살펴보라. 해당 특정 기능이 메서드 집합으로 표현되긴 했지만 컴파일러는 사실상 전송된 메시지들을 포착하여 '인라인(in-line)'으로 컴파일하여 실행을 최적화한다는 사실을 주목하라. 즉, ifTrue: 또는 ifFalse:의 정의부를 변경한다고 해서 (보통은 매우 위험한 행위다) 당신이 의도한 효과에는 영향을 미치지 않을 것이란 의미다. 또한 이 메시지를 사용하는 도중에 정확히 소스 코드의 어디에 오류가 위치하는지 가끔씩 디버거가 혼란스러워할지도 모른다.


Boolean 클래스에서 &와 and: 의 (그리고 ㅣ와 or:) 차이도 주의 깊게 살펴보아야 한다. 첫 번째 메서드 쌍은 (&와 ㅣ) 표현식을 그들의 인수로 취하고, 그 표현식을 실행하도록 보장된다. 두 번째 메서드 쌍은 (and; 와 or:) 블록을 인수로 취하고, 전체 표현식의 논리 값을 해결하는 데 그 값이 필요한 경우에 해당 블록을 실행하기만 할 것이다. 즉, 인수로서 사용되는 표현식이나 블록이 값을 리턴하는 것 외에 부가적 효과가 있을 경우, & 또는 and: (ㅣ 또는 or:)의 선택이 결정적이다. 가령 아래 두 개 중 첫 번째 표현식에서 fred는 true로 설정될 것이다. 두 번째 표현식에서는 전체 표현식이 true임을 블록이 알고 있는지 평가할 필요가 없기 때문에 true로 설정되지 않을 것이다.

(1=1)  (fred := true).
(1=1) or:  [fred := true].


해당 카테고리에서 또 다른 중요한 클래스로 UndefinedObject가 있다. 시스템은 해당 클래스의 단일 인스턴스, nil만 포함한다. UndefinedObject가 구현하는 많은 메서드들은 Object로부터 상속되는 기능을 취소(undo)하는 것과 관련된다! Nil 값은 '아무 것도 아닌(nothing)' 또는 '정의되지 않은(undefined)' 개념을 표현하는 데 사용된다. 게다가 새로 선언된 모든 변수들이 초기화되는 값이기도 하다.


마지막으로 Kernel-Objects 카테고리에서 Model 클래스는 단순히 object의 서브클래스로서, 효율성을 이유로 의존성을 다르게 구현한다 (제 8장 참조).


Kernel-Classes

이 카테고리는 스몰토크에서 진정한 '클래스'의 개념을 구현하는 모든 클래스를 포함한다. 실제로 시스템의 내부(internals)에 해당하는데, 매우 혼란스러울 수 있다. 하지만 모든 객체들이 Object 클래스에서 정의된 메시지를 이해할 수 있듯, 모든 클래스들은 Behavior, ClassDescription, Class (해당 순서대로 서로 상속됨) 클래스들에서 정의된 메시지를 이해할 수 있다는 점을 명심한다면 유용할 것이다. 이는 클래스 객체들이 Class 클래스의 인스턴스들이기 때문이다 (잘 생각해보되 혼란스럽더라도 염려할 필요 없다).


Behavior에는 매우 유용한 기능이 있는데, 특히 클래스의 서브클래스의 슈퍼클래스로의 접근하는 기능과 그것의 모든 인스턴스들을 (allInstances) 찾는 기능이다. 후자의 메시지는 디버깅 시 매우 유용하게 사용되는데, 이 메시지는 class로만 전송할 수 있음을 기억하라.


Kernel-Classes 카테고리에서 정의된 가장 중요한 단일 메시지는 아마도 new일 것이다. 이 메시지는 itself의 새 인스턴스를 만들어 리턴하도록 요청하는데, 어떤 클래스로든 전송할 수 있다. 이것이 Object의 클래스측(class side)에서 정의되어야 한다고 생각할지 모르지만 사실 스몰토크 클래스 시스템의 복잡성때문에 (여기서는 다루지 않을 작정이다) Behavior의 인스턴스측에서 정의된다. 많은 클래스들이 new 이외에 적절한 인스턴스 생성 메서드를 제공하긴 하지만 여전히 모든 클래스는 new 메시지를 이해함을 의미한다. 그러나 인스턴스를 갖지 않도록 만들어진 일부 클래스들도 (추상 슈퍼클래스) 명시적으로 새 메서드를 '구현취소(unimplement)'함을 주목한다. 이는 그것을 self shouldNotImplement 표현식으로 오버라이드하여 실행된다.


Kernel 카테고리에서 나머지는 내부적인 내용과 관련되며, 직접적으로 관심을 가진 부분은 아닐 것이다. 유일한 예로, 스몰토크 고유의 가벼운 프로세스 메커니즘으로 접근을 구현하여 제공하는 (상세한 내용은 매뉴얼을 참고) Process 클래스와, 앞장에서 살펴본 블록 개념을 구현하는 BlockClosure 클래스를 들 수 있다. BlockClosure는 클래스 계층구조에 걸쳐 간간이 섞인 스몰토크 제어 구조를 어느 정도 제공하기도 한다. 특히 repeat, whileFalse, whileTrue 메서드, 그리고 이들의 변형자(variants)가 있다. 그 구현부를 살펴보면 어떻게 작용하는지 알 수 있으며, 한 가지 예를 소개하겠다:

[MyWindow isTooBig] whileFalse: [MyWindow grow].


Interface-Framework

이를 포함해 나머지 Interface- 카테고리들은 스몰토크 사용자 인터페이스를 구현하는 모든 클래스를 포함한다. 이 카테고리들을 비롯해 uiBasics와 UILooks 카테고리들은 위젯, 윈도우, 그 중간에 해당하는 모든 것을 구현하는 수백 개의 클래스를 포함한다. 다행히 VisualWorks GUI 빌딩 툴(UZPainter와 uiBuilder 카테고리)의 존재로 인해 이 모든 클래스들을 명시적으로 접근해야 할 필요성은 극히 드물다. 하지만 접근해야 할 필요가 있다면 (그리고 VisualWorks가 지원하지 않는 사용자 인터페이스를 빌드하길 원하는 경우) 해당 카테고리에 있는 코드를 살펴보고 이해한 후 사용해야 한다. 이 클래스 중 몇 가지는 충분히 중요하며 유용한 일반 원칙들을 설명하는데, 상세한 내용은 제 10장, 이식성과 어댑터에서 설명하도록 하겠다.


Tools-Programming

해당 카테고리를 비롯해 나머지 Tools- 카테고리는 브라우저, 인스펙터, 디버거 등 우리가 제 5장에서 살펴본 대상들을 구현하는 클래스들을 포함한다. 이러한 툴이 행동하는 방식이 마음이 들지 않으면 해당 카테고리를 이용해 어떻게 작동하는지를 살펴보고 수정하면 된다.


System-Changes

해당 카테고리를 비롯해 다른 System- 카테고리들은 스몰토크 컴파일러가 사용하는 클래스들을 포함한다. 시스템 내부를 수정하길 원치 않는 한 해당 클래스 근처도 갈 필요가 없다.


OS-Window System

해당 카테고리는 스몰토크를 기반이 되는 윈도우 시스템으로 접속시키는 데 사용되는 클래스들을 포함한다. 어떤 이유로든 해당 메커니즘으로 접근성을 얻는 데 관심이 있다면 해당 카테고리를 이용한다. 하지만 일반 GUI 프로그래밍의 경우 해당 클래스를 다룰 필요가 없다. 유일한 예외가 있다면 아마 Cursor 클래스일 것이다. 이 클래스는 마우스 커서의 모양을 변경하고자 할 때 사용할 수 있는 메서드들을 제공한다.


OS-Streaming

여기서 제공하는 클래스들은 기반이 되는 운영체제 내 파일로 접근성을 지원한다. 이러한 클래스들의 인스턴스들을 직접 생성하길 원할 때가 종종 있으나 보통은 Filename 클래스의 인스턴스를 이용하면 대신 생성해준다.


OS-Support

해당 카테고리는 Filename 클래스를 포함하는데, 이는 기반이 되는 파일시스템(filesystem) 내 파일을 여는 가장 쉬운 경로다.


OS-Unix, OS-Dos, OS-Mac

해당 카테고리들은 파일명에 대한 추상적 개념과 스몰토크가 처리하는 다른 것들을 실제로 가상 머신이 실행되는 특정 플랫폼으로 특수화하는 클래스들을 포함한다. 이들은 VisualWorks가 제공하는 크로스 플랫폼 이식성을 어느 정도 가능하게 한다.


External-Collections

해당 카테고리를 비롯해 다른 External- 카테고리들은 스몰토크를 C 또는 C++와 같은 다른 언어로 연결하는 것과 관련된 엔티티(entity)를 표현하는 클래스들을 포함한다. 이것을 수행하는 방식은 대부분 자신이 가진 머신의 유형에 따라 좌우되므로 자세한 내용은 머신의 매뉴얼을 살펴볼 필요가 있겠다.


UIExamples

클래스 라이브러리에서 살펴볼 마지막으로 내용으로, 다양한 uiExamples 카테고리들은 VisualWorks 시스템의 일부로 제공되는 예제 애플리케이션들을 구현하는 데 사용되는 많은 클래스를 포함한다. 예제 애플리케이션을 수정하길 원하거나 특정 행위를 구현하는 방법을 알아낼 필요가 있다면 여기서 시작하면 되겠다.


지금까지 스몰토크 클래스 라이브러리를 소개해보았다. 여정을 함께 했다면 많은 시스템 클래스에 존재하는 표준 프로토콜에 이미 익숙해지고 있음을 발견할 것이다 (본문에 제공된 설명과 브라우징을 통해). 프로토콜이 포함하게 될 메서드 유형을 프로토콜명에서 어떻게 예측하는지도 어느 정도 알게 되었을 것이다.


이제 모든 객체가 이해하는 메시지(Object에서 정의된), 모든 클래스가 이해하는 메시지(Behavior, ClassDescription, Class에서 정의된)에 대해서도 어느 정도 이해할 것이다.


정의된 산술 연산을 어디서 찾는지 (ArithmeticValue와 그 서브클래스), 논리 연산과 제어 구조를 어디서 찾는지도 (Boolean과 그 서브클래스) 학습했을 것이다. 마지막으로 나머지 클래스 라이브러리가 어떤 유형의 기능을 포함하는지도 잘 이해할 것이다.


본 저서의 나머지 부분은 여기서 언급한 기능과 클래스를 좀 더 상세히 설명하고 있다. 선택된 클래스들은 이해하고 나면 유용할 뿐만 아니라 훌륭한 스몰토크 프로그래밍의 스타일을 설명하기 때문에 선택되었다. 제 2부는 나아가 스몰토크 시스템을 스스로 학습하는 방법을 설명하고, 더 중요한 것은 자연스럽게 자신만의 클래스를 디자인하는 방법을 설명한다.


Notes