Smalltalk80LanguageImplementationKor:Chapter 10

From 흡혈양파의 번역工房
Revision as of 10:35, 10 July 2015 by Onionmixer (talk | contribs) (bluebook kor chapter 10 한글번역 추가)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
제 10 장 컬렉션 클래스의 계층구조

컬렉션 클래스의 계층구조

Object

    Magnitude
        Character
        Date
        Time

        Number
            Float
            Fraction
            Integer
                LargeNegativeInteger
                LargePositiveInteger
                SmallInteger

        LookupKey***
            Association***

    Link***

        Process

    Collection

        SequenceableCollection***
            LinkedList***

                Semaphore

            ArrayedCollection***
                Array***

                Bitmap
                    DisplayBitmap

                RunArray***
                String***
                    Symbol***
                Text***
                ByteArray***

            Interval***
            OrderedCollection***
                SortedCollection***
        Bag***
        MappedCollection***
        Set***
            Dictionary***
                IdentifyDictionary***

    Stream
        PositionableStream
            ReadStream
            WriteStream
                ReadWriteStream
                    ExternalStream
                        FileStream

        Random

    File
    FileDirectory
    FilePage

    UndefinedObject
    Boolean
        False
        True

    ProcessorScheduler
    Delay
    SharedQueue

    Behavior
        ClassDescription
            Class
            MetaClass

    Point
    Rectangle
    BitBit
        CharacterScanner

        Pen

    DisplayObject
        DisplayMedium
            Form
                Cursor
                DisplayScreen
        InfiniteForm
        OpaqueForm
        Path
            Arc
                Circle
            Curve
            Line
            LinearFit
            Spline


그림 10.1은 시스템 내 다양한 컬렉션 클래스를 구분하기 위한 로드맵이다. 그림에서 선택을 따라가다보면 구현에서 사용할 컬렉션 유형을 선택하는 데에 유용할 것이다.

그림 10-1


클래스를 구분하는 한 가지 방법은 컬렉션이 그 요소들과 잘 정의된 순서를 갖고 있는지 여부와 관련된다. 또 일부 클래스의 요소들은 “keys”(키) 또는 외부적으로 알려진 이름을 통해 접근이 가능하다. 키의 타입은 컬렉션 유형을 구분하는 또 다른 방도를 정의한다. 일부는 정수 색인으로, 요소의 순서에 따라 암묵적으로 할당되고, 그 외에는 명시적으로 할당된 객체들로서 검색 키(look up key) 역할을 한다.


외부 키를 가진 정렬되지 않은 컬렉션으로는 Dictionary가 있다. 그 키는 주로 String 또는 LookupKey의 인스턴스로, 매칭 키의 비교에는 상등부호(=)가 사용된다. Dictionary에는 외부 키가 주로 Symbols에 해당하는 IdentifyDictionary 서브클래스가 포함되어 있다. 매칭 키의 비교에는 동등성(==)을 사용한다. Bag 또는 Set의 요소들은 정렬되지 않고, 외부에서 알려진 키를 통해 접근할 수 없다. 중복은 Bag에선 허용되지만 Set에선 허용되지 않는다.


모든 정렬된 컬렉션은 SequenceableCollections 형이다. 모든 SequenceableCollections의 요소들은 정수 색인에 해당하는 키를 통해 접근할 수 있다. SequenceableCollection의 네 가지 서브클래스는 요소의 정렬을 생성하는 여러 방법들을 지원한다. SequenceableCollection 클래스를 서로 구별하는 한 가지 추가적인 방법은 요소가 어떤 객체든 가능한지 또는 요소가 특정 객체의 인스턴스로 제한되어 있는지 여부를 확인하는 것이다.


OrderedCollections, LinkedLists, ArrayedCollections에서 요소의 순서는 외부적으로 결정된다. OrderedCollection과 LinkedList의 경우 프로그래머가 요소를 추가하고 제거하는 시퀀스가 요소의 순서를 정의한다. OrderedCollection의 요소는 어떤 객체든 가능한 반면 LinkedList의 요소는 Link와 동일한 유형이어야 한다. 시스템 내 또 다른 ArrayedCollections로는 Array, String, ByteArray가 있다. Array 또는 RunArray의 요소는 어떤 유형의 객체든 가능하고, String 또는 Text의 요소들은 Characters여야 하며, ByteArray의 요소는 0부터 255까지 SmallIntegers여야 한다.


Intervals와 SortedCollections의 경우 요소의 순서는 내부적으로 결정된다. Interval의 경우 순서는 인스턴스가 생성될 당시 명시된 등차수열에 해당한다. SortedCollection의 경우 순서는 컬렉션에 알려진 블록을 평가함으로써 결정된 정렬 기준이 명시한다. Interval의 요소는 Numbers여야 하고, SortedCollection의 요소는 어떤 객체든 가능하다.


이미 언급한 컬렉션 클래스 외에도 외부 키를 통해 요소로 접근이 가능한 컬렉션에 대한 간접 접근 경로를 나타내는 Collection으로 MappedCollection이 있다. 한 가지 외부 키의 집합으로부터 컬렉션으로 매핑은 MappedCollection이 생성될 당시 결정된다.


본 장의 나머지 부분에 걸쳐 메시지 프로토콜을 추가 설명하고 간단한 예를 소개함으로써 컬렉션 서브클래스를 하나씩 살펴보도록 하겠다.


Bag 클래스

Bag은 가장 간단한 컬렉션 유형이다. 요소가 정렬되지 않고 외부 키가 없는 컬렉션을 나타낸다. Bag은 Collection의 서브클래스다. Bag의 인스턴스들은 외부 키를 갖지 않기 때문에 at: 과 at:put: 메시지에 응답할 수 없다. size 메시지는 컬렉션의 총 요소 개수를 응답한다.


Bag은 모든 컬렉션의 프로토콜에 따라 행동하는 요소 집단에 불과하다. 컬렉션에 대한 일반적인 설명에서는 각 컬렉션에서 요소의 발생 횟수를 제한하지 않는다. Bag 클래스는 요소를 추가하기 위한 추가 메시지를 명시함으로써 일반성을 강조한다.

추가하기(adding)
add: newObject withOccurrences: anInteger newObject 인자를 수신자의 요소로서 anInteger 횟수만큼 포함한다.
Bag 인스턴스 프로토콜


식품 항목과 가격을 나타내는 Product 클래스를 예로 들어보자. of: name at: price 메시지를 이용해 새로운 Product를 생성할 수 있으며, 인스턴스의 가격은 price 메시지를 전송함으로써 접근이 가능하다. 어떤 사람의 쇼핑백(grocery bag)을 채우는 것은 아래와 같이 표현할 수 있다.

sack  Bag new.
sack add: (Product of: #steak at: 5.80).
sack add: (Product of: #potatoes at: 0.50) with Occurrences: 6.
sack add: (Product of: #carrots at: 0.10) withOccurrences: 4.
sack add: (Product of: #milk at: 2.20)


그리고 식료품 계산서는 아래와 같은 표현식이나

amount  0.
sack do: [ :eachProduct | amount  amount + eachProduct price]


아래의 표현식으로 결정되어

sack inject: 0
    into: [ :amount :eachProduct | amount + eachProduct price]


$11.40이 된다. Bag으로 전송되는 add:, do:, inject:into: 메시지는 그 슈퍼클래스 Collection으로부터 상속됨을 주목한다.


Bag은 정렬되지 않으므로 열거 메시지가 지원된다 하더라도 프로그래머는 요소가 열거되는 순서에 의존할 수 없다.


Set 클래스

Set 클래스는 요소가 정렬되지 않고 외부 키를 갖고 있지 않는 컬렉션을 나타낸다. Set의 인스턴스는 at: 과 at:put: 메시지에 응답할 수 없다. Set은 Bag과 동일한데, 유일한 차이점은 Set의 경우 요소들이 중복이 불가하다는 점이다. 추가 메시지는 컬렉션에 요소가 없을 때에만 추가한다. Set 클래스는 Collection 클래스의 서브클래스다.


Dictionary 클래스와 IdentityDictionary 클래스

Dictionary 클래스는 키와 값 사이의 연관 집합을 나타낸다. Dictionary의 요소들은 키-값 쌍 멤버를 저장 및 검색하는 간단한 데이터 구조체인 Association 클래스의 인스턴스다.


Dictionary를 또 다른 방식으로 생각하자면, 요소가 정렬되어 있진 않지만 명시적으로 할당된 키나 이름을 가진 컬렉션으로 설명할 수도 있겠다. 이러한 관점에서 보면 Dictionary의 요소들은 외부 키가 있는 임의의 객체(값)들로 볼 수 있겠다. Dictionary를 생각하는 이러한 대안적 관점들이 클래스의 메시지 프로토콜에 반영된다. includes:, do:, 그 외 열거 메시지를 포함해 Collection으로부터 상속된 메시지들은 Dictionary의 “values”(값)에 적용된다. 즉, 이러한 메시지들은 키나 연관 자체가 아니라 Dictionary 내 각 연관의 값을 참조한다.


Object 클래스로부터 상속된 메시지 at: 과 at:put:는 Dictionary의 키에 적용된다. at: 과 at:put: 패러다임은 associationAt: 과 keyAtValue: 메시지를 추가함으로써 연관 및 값으로 확장된다. Dictionary에서 요소를 검색할 때 추가 제어를 제공하기 위해 at:if:Absent: 메시지가 제공되는데, 프로그래머는 이를 이용해 첫 번째 인자를 키로 가진 요소가 발견되지 않으면 취하게 될 액션을 명시할 수 있다. 키가 발견되지 않으면 상속된 메시지 at: 은 오류를 보고한다.

접근하기(accessing)
at: key ifAbsent: aBlock key 인자가 명명한 값을 응답한다. key가 발견되지 않으면 aBlock의 평가 결과를 응답한다.
associationAt: key key 인자가 명명한 연관을 응답한다. key가 발견되지 않으면 오류를 보고한다.
associationAt: key ifAbsent: aBlock key 인자가 명명한 연관을 응답한다. key가 발견되지 않으면 aBlock의 평가 결과를 응답한다.
keyAtValue: value value 인자에 대한 이름을 응답한다. 해당 값이 없다면 nil을 응답한다. 값이 꼭 유일할 필요는 없으므로 검색에서 처음으로 찾은 이름을 응답한다.
keyAtValue: value ifAbsent: exceptionBlock value 인자에 대한 키를 응답한다. 해당 값이 없다면 exceptionBlock 의 평가 결과를 응답한다.
keys 수신자의 키를 포함하는 Set을 응답한다.
values 수신자의 값을 포함하는 Bag을 응답한다 (중복도 포함).
Dictionary 인스턴스 프로토콜


Dictionary의 사용 예로, opposites가 Symbols라는 단어와 그 opposites로 구성된 Dictionary라고 가정하자.

opposites  Dictionary new.
opposites at: #hot put: #cold.
opposites at: #push put: #pull.
opposites at: #stop put: #go.
opposites at: #come put: #go


아니면 Association을 인자로 생성함으로써 add: 메시지를 이용해 요소를 추가할 수도 있다.

opposites add: (Association key: #front value: #back).
opposites add: (Association key: #top value: #bottom)


opposites라는 Dictionary는 이제 다음과 같이 구성된다.

키(key)
hot cold
push pull
stop go
come go
front back
top bottom


Collection 클래스로부터 상속된 검사 프로토콜을 이용해 Dictionary의 값을 검사할 수 있다. includes: 은 키가 아니라 값의 포함을 검사한다.

표현식 결과
opposites size 6
opposites includes: #cold true
opposites includes: #hot false
opposites occurrencesOf: #go 2
opposites at: #stop put: #start start


네 번째 예는, 키가 Dictionary에서 나타나는 횟수는 한 번이지만 값은 몇 개의 키와도 연관될 수 있음을 나타낸다. 마지막 예제에서는 #stop 키를 새로운 값 #start와 다시 연관시킨다. 연관과 키를 검사하기 위한 추가 메시지가 Dictionary 클래스에서 제공된다.

dictionary 검사하기
includesAssociation: anAssociation 수신자가 anAssociation 인자와 동일한 요소를 (키와 값 사이의 연관) 갖는지 응답한다.
includesKey: key 수신자가 key 인자와 동일한 키를 갖는지 응답한다.
Dictionary 인스턴스 프로토콜


그리고 다음과 같이 시도해볼 수 있다.

표현식 결과
opposites includesAssociation:(Association key: #come value: #go) true
opposites includesKey: #hot true


이와 비슷하게 Collection 클래스에 명시된 제거 프로토콜을 확장시켜 값뿐만 아니라 연관과 키로의 참조를 통해 접근하는 방법도 제공한다. 하지만 remove: 메시지 자체는 Dictionary에 적합하지 않은데, 요소를 제거 시 키를 언급해야 하기 때문이다.

dictionary 제거하기
removeAssociation: anAssociation 키와 값 연관 anAssociation을 수신자로부터 제거한다. anAssociation을 응답한다.
removeKey: key 수신자에게서 키(와 그에 연관된 값)를 제거한다. 수신자에게서 key가 발견되지 않으면 오류를 보고한다. key가 발견되면 key와 연관된 값을 응답한다.
수신자에게서 키(와 그에 연관된 값)를 제거한다. 수신자에게서 key가 발견되지 않으면 aBlock의 평가 결과를 응답한다. 키가 발견되면 key가 명명한 값을 응답한다.
Dictionary 인스턴스 프로토콜


예를 들면 다음과 같다.

expression result
opposites removeAssociation: (Association key: #top value: #bottom) 키가 #top이고 값이 #bottom인 연관. opposites의 요소 수는 하나 더 적다.
opposites removeKey: #hot 키가 #hot이고 값이 #cold인 연관. 해당 연관은 opposites로부터 제거된다.
opposites removeKey: #cold ifAbsent: [opposites at: #cold put: #hot] hot


마지막 예제의 결과 #hot과 #cold의 연관이 opposites의 요소가 된다.


do: 메시지는 Dictionary의 각 값마다 그 인자인 블록을 평가한다. 연관과 키의 열거를 위한 메시지를 제공하기 위해 Collection 클래스로부터 상속된 컬렉션 열거 프로토콜은 다시 확장된다. reject: 과 inject:into: 의 사용을 지원하는 메시지는 제공되지 않는다.

dictionary 열거하기
associationsDo: aBlock 수신자의 키/값 연관마다 aBlock을 평가한다.
keysDo: aBlock 수신자의 키마다 aBlock을 평가한다.
Dictionary 인스턴스 프로토콜


따라서 Dictionary에서 가능한 열거 방법이 세 가지가 된다. newWords는 아동이 아직 배우지 않은 단어의 Set이다. opposites에 있는 단어라면 이제 아동의 레퍼토리(repertoire)에 속하고 newWords에서 제거될 수 있다. 아래 두 개의 표현식을 평가하면 이러한 단어가 제거된다 (첫 번째는 값을 제거하고, 두 번째는 키를 제거한다).

opposites do: [ :word | newWords remove: word ifAbsent: []].
opposites keysDo: [ :word | newWords remove: word ifAbsent: []]


opposites의 단어가 newWords에 있지 않으면 어떤 일도 (어떤 오류 보고도) 발생하지 않음을 주목한다. 이 대신 Associations를 열거하는 한 가지 표현식을 이용할 수 있다.

opposites associationsDo:
    [ :each |
        newWords remove: each key ifAbsent: [].
        newWords remove: each value ifAbsent: []]


접근 메시지 keys와 values를 이용해 opposites 사전에서 단어 모음을 얻을 수 있다. 앞의 모든 표현식 예제를 가정하면,

opposites keys


위는 아래와 같은 요소들을 가진 Set을 리턴하고,

push come front stop cold


아래는

opposites values


아래와 같은 요소를 가진 Bag을 리턴한다.

pull go back start hot


SequenceableCollection 클래스

SequenceableCollection 클래스는 요소가 정렬되어 있고 정수 색인에 의해 외부적으로 명명되는 컬렉션을 나타낸다. SequenceableCollection은 Collection의 서브클래스로, 요소와 연관된 순서가 존재한다는 사실이 알려지면 컬렉션의 요소로 접근, 복사, 열거하기 위한 프로토콜을 제공한다. 요소가 정렬되어 있기 때문에 컬렉션에는 잘 정의된 first와 last 요소가 있다. 컬렉션 내에서 특정 요소(index:Of:)의 색인과 요소의 시퀀스 시작에 대한 색인을 (indexOfSubCollection:startingAt:) 요청할 수 있다. 제 6장에 설명한 바와 같이 at:, at:put:, size에 해당한다. 또 SequenceableCollections는 Collection의 요소가 명명한 모든 위치로 객체를 놓는 것이 가능하며 (atAll:put:), 시퀀스 내 모든 위치로 객체를 놓는 것도 가능하다 (atAllPut:). 컬렉션 내 요소의 시퀀스는 다른 컬렉션의 요소로 대체 가능하다(replaceFrom:to:with: 와 replaceFrom:to:with:startingAt:).

접근하기(accessing)
atAll: aCollection put: anObject aCollection 인자의 각 요소를 (Integer 또는 다른 외부 키) 두 번째 인자 anObject와 연관시킨다.
atAllPut: anObject anObject 인자를 수신자의 요소 각각으로 넣는다.
first 수신자의 첫 번째 요소를 응답한다. 수신자가 요소를 포함하지 않으면 오류를 보고한다.
last 수신자의 마지막 요소를 응답한다. 수신자가 요소를 포함하지 않으면 오류를 보고한다.
indexOf: anElement 수신자 안에서 anElement 인자의 첫 번째 색인을 응답한다. 수신자가 anElement를 포함하지 않으면 0을 응답한다.
indexOf: anElement ifAbsent: exception Block 수신자 안에서 anElement 인자의 첫 번째 색인을 응답한다. 수신자가 anElement를 포함하지 않으면 exceptionBlock 인자의 평가 결과를 응답한다.
indexOfSubCollection: aSubCollection startingAt: anIndex aSubCollection 인자의 요소들이 수신자 안에 순서대로 나타나면 첫 번째 발생의 첫 번째 요소에 대한 색인을 응답한다. 매치가 발견되지 않으면 0을 응답한다.
indexOfSubCollection: aSubCollection startingAt: anIndex ifAbsetnt: exceptionBlock 수신자의 첫 번째 요소의 색인을 응답하되, 해당 요소는 aSubCollection 인자의 첫 번째 요소와 동일해야 하고 그 다음 요소들은 aSubCollection의 나머지 요소들과 동일해야 한다. anIndex 인자를 색인으로 가진 요소에서 수신자의 검색을 시작한다. 매치가 발견되지 않으면 exceptionBlock 인자의 평가 결과를 응답한다.
replaceFrom: start to: stop with: replacementCollection start와 stop 사이의 각 색인을 replacementCollection 인자의 요소와 연관시킨다. 수신자를 응답한다. replacementCollection 내에 요소의 개수는 stop-start + 1과 같아야 한다.
replaceFrom: start to: stop with: replacementCollection startingAt: repStart start와 stop 사이의 각 색인을 replacementCollection 인자의 요소와 연관시키되 repStart를 색인으로 가진 replacementCollection의 요소부터 시작한다. 수신자를 응답한다. 어떠한 범위 검사도 실행되지 않지만 한 가지 예외가 있는데, 수신자가 replacementCollection과 같으나 repStart가 1이 아닌 경우 색인이 범위를 벗어났음을 보고하는 오류가 발생할 것이란 점이다.
SequenceableCollection 인스턴스 프로토콜


String의 인스턴스를 이용한 이러한 접근 메시지의 활용 예는 다음과 같다.

표현식 결과
'aaaaaaaaaa' size 10
'aaaaaaaaaa' atAll: (2 to: 10 by: 2) put: $b 'ababababab'
'aaaaaaaaaa' atAllPut: $b 'bbbbbbbbbb'
'This string' first $T
'This string' last $g
'ABCDEFGHIJKLMNOP' indexOf: $F 6
'ABCDEFGHIJKLMNOP' indexof: $M ifAbsent: [0] 13
'ABCDEFGHIJKLMNOP' indexOf: $Z ifAbsent: [0] 0
'The cow jumped' indexOfSubCollection: 'cow' startingAt: 1 5
'The cow jumped' replaceFrom: 5 to: 7 with: 'dog' 'The dog jumped'
'The cow jumped' replaceFrom: 5 to: 7 with: 'the spoon ran' startingAt: 5 'The spo jumped'


이러한 예제들은 SequenceableCollection의 어떤 서브클래스의 인스턴스든 실행 가능한데, Array를 예를 들 수 있겠다. Array의 경우 brown 대신 black인 #(brown jug)가 아래의 표현식을 평가함으로써 실행된다.

#(The brown jug) replaceFrom: 2 to: 2 with: #(black)


마지막 인자도 Array여야 한다는 점을 명심한다. 그리고 대체 메시지는 컬렉션을 수정하긴 하지만 원본 컬렉션(수신자)의 크기를 변경하지는 않음을 주목한다. 복사본을 생성하여 원본을 유지하는 편을 선호할 수도 있다. SequenceableCollections 의 복사 프로토콜은 컬렉션 내 요소의 시퀀스 복사, 컬렉션의 일부만 대체한 전체 컬렉션의 복사, 한 가지 요소만 제거된 전체 컬렉션의 복사, 하나 또는 이상의 요소가 연결된 전체 컬렉션의 복사를 지원한다.

복사하기(copying)
, aSequenceableCollection 연결(concatenation) 연산이다. aSequenceableCollection 인자의 각 요소가 순서대로 정렬된 수신자의 복사본을 응답한다.
copyFrom: start to: stop start 색인에 있는 요소부터 stop 색인에 있는 요소까지 수신자의 하위집합 복사본을 응답한다.
copyReplaceAll: oldSubCollection with: newSubCollection oldSubCollection의 모든 발생이 newSubCollection으로 대체된 수신자의 복사본을 응답한다.
copyReplaceFrom: start to: stop with: replacementCollection 아래 조건을 충족하는 수신자의 복사본을 응답한다. stop이 start보다 작을 경우 삽입에 해당하고, stop이 정확히 start-1일 경우 start=1은 첫 번째 문자 앞에 삽입을 의미하며, start=size+1은 마지막 문자 뒤에 추가를 의미한다. 그 외의 경우 대체를 실행하고, start와 stop은 수신자의 범위 내에 있어야 한다.
copyWith: newElement 수신자보다 1이 크고 newElement를 마지막 요소로 가진 수신자의 복사본을 응답한다.
copyWithout: oldElement oldElement의 모든 발생이 제거된 수신자의 복사본을 응답한다.
SequenceableCollection 인스턴스 프로토콜


대체 및 복사 메시지를 이용해 간단한 텍스트 에디터를 만들 수 있다. Smalltalk-80 시스템은 Text 클래스뿐만 아니라 String 클래스도 포함하는데, Text 클래스는 문자의 글꼴, 볼드체, 이탤릭체, 밑줄을 혼합하기 위해 글꼴이나 강조의 변경과 String 내에 문자의 연관을 지원한다. Text에 대한 메시지 프로토콜은 강조 코드를 설정하기 위한 추가 프로토콜이 있는 SequenceableCollection의 프로토콜이다. 사용 예제를 설명하기 위해 String 클래스의 인스턴스를 사용할 것인데, Text 클래스의 인스턴스에 편집 메시지를 동일하게 적용할 수 있음을 상기시킬 것이다. line은 처음에 빈 문자열로 가정한다.

line  String new: 0


이를 적용하면 다음과 같다.

표현식 결과
line ← line copyReplaceFrom: 1 to: 0 with: 'this is the first line tril' 'this is the first line tril'
line ← line copyReplaceAll: 'tril' with: 'trial' 'this is the first line trial'
line ← line copyReplaceFrom: (line size + 1) to: (line size) with: 'and so on' this is the first line trial and so on'
line indexOfSubCollection: 'trial' startingAt: 1 24
line ← line copyReplaceFrom: 29 to: 28 with: ' ' 'this is the first line trial and so on'


위에 제공한 복사 프로토콜의 마지막 두 메시지는 요소의 유무와 상관없이 Array의 복사본을 얻는 데에 유용하다. 다음을 예로 들 수 있겠다.

표현식 결과
#(one two three) copyWith: #four (one two three four)
#(one two three) copyWithout: #two (one three)


SequenceableCollection의 요소는 정렬되어 있으므로 첫 번째 요소부터 시작해 연속된 요소를 끝까지 취하여 순서대로 열거가 이루어진다. reverseDo: aBlock 메시지를 이용한 역 열거(reverse enumeration)도 가능하다. 두 개의 SequenceableCollection 열거도 함께 가능하므로 각 컬렉션에서 하나씩 취한 요소의 쌍을 이용해 블록을 평가할 수 있다.

열거하기(enumerating)
findFirst: aBlock 수신자의 각 요소를 인자로 하여 aBlock을 평가한다. 인자 aBlock이 true로 평가하는 첫 번째 요소의 색인을 응답한다.
findLast: aBlock 수신자의 각 요소를 인자로 하여 aBlock을 평가한다. 인자 aBlock이 true로 평가하는 마지막 요소의 색인을 응답한다.
reverseDo: aBlock 수신자의 각 요소를 인자로 하여 aBlock을 평가하되 마지막 요소부터 시작해 시퀀스에서 첫 번째 요소까지 취한다. SequenceableCollections의 경우 이는 do: 에 대한 열거의 역에 해당한다. aBlock은 1인자 블록이다.
with: aSequenceableCollection do: aBlock 수신자와 각 요소와 함께 aSequenceableCollection로부터 상응하는 요소에 aBlock을 평가한다. aSequenceableCollection은 수신자의 크기와 같아야 하며 aBlock은 2인자 블록이어야 한다.
SequenceableCollection 인스턴스 프로토콜


아래 표현식은 앞의 예제에서 소개한 Dictionary인 opposites를 생성한다.

opposites  Dictionary new.
#(come cold front hot push stop)
    with: #(go hot back cold pull start)
    do: [ :key :value | opposites at: key put: value]


이제 Dictionary는 6개의 연관을 요소로 갖게 된다.


SequenceableCollectiion은 Array 또는 MappedCollection으로 변환이 가능하다. 메시지는 asArray 와 mappedBy: aSequenceableCollection이다.


SequenceableCollection의 서브클래스

SequenceableCollection의 서브클래스로는 OrderedCollection, LinkedList, Interval, MappedCollection이 있다. ArrayedCollection은 고정된 범위의 정수를 외부 키로 가지는 요소의 컬렉션을 나타낸다. ArrayedCollection 의 서브클래스 예로 Array와 String을 꼽을 수 있다.

OrderedCollection 클래스

OrderedCollections 클래스는 객체가 추가되고 제거되는 순서대로 정렬된다. 요소는 색인에 해당하는 외부 키에서 접근할 수 있다. 접근, 추가, 제거 프로토콜은 첫 번째와 마지막 요소, 그리고 다른 요소들의 앞에 오거나 뒤에 오는 요소들을 참조하도록 늘어난다.


OrderedCollections는 "stacks"(스택) 또는 "quese"(큐)의 역할을 할 수 있다. 스택은 순차 리스트로서 리스트의 한쪽 끝에서 ("rear"(뒤) 또는 "front"(앞)라 불림) 모든 추가와 삭제가 이루어진다. 종종 "last-in first-out"(후입선출) 큐라고 불린다.

일반 용어(usual vocabulary) OrderedCollection 메시지
push newObject addLast: newObject
pop removeLast
top last
empty isEmpty


큐는 리스트 한쪽 끝에서 한 번에 모든 추가가 이루어지고 ("뒤") 다른 끝에서 ("앞") 모든 제거가 이루어지는 순차 리스트를 의미한다. 이러한 방식을 "first-in first-out"(선입 선출) 큐라고 부르곤 한다.

일반 용어(usual vocabulary) OrderedCollection 메시지
add newObject addLast: newObject
delete removeFirst
front first
empty isEmpty


OrderedCollection 로 add: 메시지를 전송한다는 것은 "요소를 컬렉션의 마지막 member로 추가하라"는 의미이고, remove: 은 "요소로서 인자를 제거하라" 는 의미다. Collection과 SequenceableCollection 클래스에서 상속된 것을 비롯해 OrderedCollections의 메시지 프로토콜은 다음과 같다.

접근하기(accessing)
after: oldObject 수신자 내에서 oldObject 뒤에 오는 요소를 응답한다. 수신자가 oldObject를 포함하지 않거나 oldObject 뒤에 요소가 없다면 오류를 보고한다.
before: oldObject 수신자 내에서 oldObject 앞에 오는 요소를 응답한다. 수신자가 oldObject를 포함하지 않거나 oldObject 앞에 요소가 없다면 오류를 보고한다.
추가하기(adding)
add: newObject after: oldObject newObject 인자를 수신자의 요소로서 추가한다. 이를 시퀀스에서 oldObject 바로 뒤에 놓아라. newObject를 응답한다. oldObject를 찾을 수 없다면 오류를 보고한다.
add: newObject before: oldObject newObject 인자를 수신자의 요소로서 추가한다. 이를 시퀀스에서 oldObject 바로 앞에 놓아라. newObject를 응답한다. oldObject를 찾을 수 없다면 오류를 보고한다.
addAllFirst: anOrderedCollection 수신자 시작 위치에 anOrderedCollection 인자의 각 요소를 추가한다. anOrderedCollection을 응답한다.
addAllLast: anOrderedCollection 수신자 끝 위치에 anOrderedCollection 인자의 각 요소를 추가한다. anOrderedCollection을 응답한다.
addFirst: newObject 수신자 시작 위치에 newObject 인자를 추가한다. newObject를 응답한다.
addLast: newObject 수신자 끝 위치에 newObject 인자를 추가한다. newObject를 응답한다.
제거하기(removing)
removeFirst 수신자의 첫 번째 요소를 제거하고 응답한다. 수신자가 비어 있다면 오류를 보고한다.
removeLast 수신자의 마지막 요소를 제거하고 응답한다. 수신자가 비어 있다면 오류를 보고한다.
OrderedCollection 인스턴스 프로토콜


SortedCollection 클래스

SortedCollection 클래스는 OrderedCollection의 서브클래스다. SortedCollection의 요소들은 두 개의 요소의 함수에 따라 정렬된다. 함수는 정렬 블록(sort block)이라는 2인자 블록에 의해 표현된다. add: 메시지를 이용해야만 요소를 추가할 수 있으며, 삽입 순서를 프로그래머가 명시하도록 해주는 addLast: 과 같은 메시지들은 SortedCollections에선 허용되지 않는다.


SortedCollection 클래스의 인스턴스는 SortedCollection에 sortBlock: 메시지를 전송하여 생성할 수 있다. 이 메시지에 대한 인자는 2인자의 블록으로, 아래를 예로 들 수 있다.

SortedCollection sortBlock: [ :a :b | a < = b ]


이 특정 블록은 SortedCollection으로 new 메시지를 전송하면 간단히 인스턴스가 생성되는 기본 정렬 함수다. 따라서 SortedCollection을 생성하는 네 가지 방법의 예를 아래와 같이 들 수 있다.

SortedCollection new
SortedCollection sortBlock: [ :a :b | a > b ]
anyCollection asSortedCollection
anyCollection asSortedCollection: [ :a :b | a > b ]


SortedCollection의 인스턴스로 두 가지 추가적 접근 메시지를 이용해 블록을 결정하고 블록을 리셋하는 것도 가능하다. 블록이 변경되면 컬렉션의 요소도 물론 재정렬된다. 특정 정렬 기준의 인스턴스를 생성하기 위해 클래스 자체로 (sortBlock:) 전송되는 메시지는 정렬 기준을 변경하기 위해 인스턴스로 전송되는 메시지와 동일함을 주목한다.

인스턴스 생성
sortBlock: aBlock aBlock 인자에 명시된 기준에 따라 요소가 정렬될 SortedCollection의 인스턴스를 응답한다.
SortedCollection 인스턴스 프로토콜


접근하기(accessing)
sortBlock 수신자의 요소를 정렬하는 기준에 해당하는 블록을 응답한다.
sortBlock: aBlock aBlock 인자를 수신자의 요소를 정렬하는 기준으로 만든다.
SortedCollection 클래스 프로토콜


학급에서 아동의 이름을 알파벳으로 정리한 목록을 유지한다고 가정하자.

children  s=SortedCollection new


처음 정렬 기준은 기본 블록 [ :a :b | a < = b]다. 컬렉션 요소는 Strings이거나 Symbols가 될 수 있는데, 곧 설명하겠지만 이러한 유형의 객체들은 <, >, < =, > = 와 같은 비교 메시지에 응답할 수 있기 때문이다.

표현식 결과
children add: #Joe Joe
children add: #Bill Bill
children add: #Alice Alice
children SortedCollection(Alice Bill Joe)
children add: #Sam Sam
a < b ] SortedCollection(Sam Joe Bill Alice)
children add: #Henrietta Henrietta
children SortedCollection(Sam Joe Henrietta Bill Alice)


예제에서 6번째 메시지는 children 컬렉션에서 요소가 저장되는 순서를 역전하였다.


LinkedList 클래스

LinkedList는 객체가 추가되고 제거되는 순서대로 요소가 명시적으로 정렬되는 SequenceableCollection의 또 다른 서브클래스다. OrderedCollection과 마찬가지로 LinkedList의 요소들은 색인에 해당하는 외부 키에 의해 참조된다. 요소가 어떤 객체든 될 수 있는 OrderedCollection과 달리 LinkedList의 요소들은 동질하므로 각 요소는 Link 클래스의 인스턴스 또는 Link의 서브클래스가 되어 있어야 한다.


Link는 다른 Link로의 참조에 대한 기록이다. 그 메시지 프로토콜은 이러한 메시지들로 구성된다. 특정 참조를 가진 Link의 인스턴스를 생성하거나 인스턴스의 참조를 변경할 때도 동일한 메시지를 (nextLink:) 이용할 수 있다.

인스턴스 생성
nextLink: aLink aLink 인자를 참조하는 Link의 인스턴스를 생성한다.
LinkedList 클래스 프로토콜


접근하기(accessing)
nextLink 수신자의 참조를 응답한다.
nextLink: aLink 수신자의 참조를 aLink 인자로 설정한다.
LinkedList instance protocol


컬렉션의 실제 요소로 참조를 기록하는 방법은 Link 클래스에서 제공하지 않으므로 추상적 클래스로 취급된다. 즉, Link 클래스의 인스턴스는 생성되지 않는다는 말이다. 대신 서브클래스가 하나 또는 그 이상의 요소를 정렬하는 매커니즘을 제공하도록 정의되고 서브클래스의 인스턴스가 생성된다.


LinkedList는 SequenceableCollection의 서브클래스이므로 그 인스턴스들은 모든 컬렉션에 대해 정의된 접근, 추가, 제거, 열거 메시지에 응답할 수 있다. LinkedList에 대한 추가 프로토콜은 다음과 같이 구성된다.

추가하기(adding)
addFirst: aLink 수신자의 목록 시작에 aLink를 추가한다. aLink를 응답한다.
addLast: aLink 수신자의 목록 끝에 aLink를 추가한다. aLink를 응답한다.
제거하기(removing)
removeFirst 수신자의 첫 번째 요소를 제거하고 응답한다. 수신자가 비어 있다면 오류를 보고한다.
removeLast 수신자의 마지막 요소를 제거하고 응답한다. 수신자가 비어 있다면 오류를 보고한다.
LinkedList 인스턴스 프로토콜


Smalltalk-80에서 Link의 서브클래스 예로 Process 클래스를 들 수 있다. Semaphore는 LinkedList의 서브클래스다. 이 두 개의 클래스는 시스템에 내 다중 독립 프로세스를 설명한 제 15장에서 논하고 있다.


아래는 LinkedList의 사용예를 소개하겠다. Link는 다른 Link로의 참조 외에는 어떠한 인스턴스 정보도 제공하지 않는다. 그러므로 Entry 라는 Link의 서브클래스가 있다고 가정해보자. Entry는 하나의 객체를 저장할 수 있는 기능을 추가한다. Entry에 대한 인스턴스 생성 메시지는 for:anObject이고, 그 접근 메시지는 element다.

클래스명 Entry
슈퍼클래스 Link
인스턴스 변수명 element
클래스 메서드
instance creation
    for: anObject
        self new setElement: anObject
인스턴스 메서드
accessing
    element
        element

printing
    printOn: aStream
        aStream nextPutAll: 'Entry for:', element printString

private
    setElement: anObject
        element  anObject


LinkedList 클래스와 Entry 클래스는 아래와 같이 사용할 수 있다.

표현식 클래스
link ← LinkedList new LinkedList ()
list add: (Entry for: 2) Entry for: 2
list add: (Entry for: 4) Entry for: 4
list addLast: (Entry for: 5) Entry for: 5
list addFirst: (Entry for: 1) Entry for: 1
list LinkedList (Entry for: 1 Entry for: 2 Entry for: 4 Entry for: 5)
list isEmpty false
list size 4
(each element) + value ] 12
list last Entry for: 5
list first Entry for: 1
list remove: (Entry for:4) Entry for: 4
list removeFirst Entry for: 1
list removeLast Entry for: 5
list first = = list last true


Interval 클래스

또 다른 SequenceableCollection 유형으로 수학적 과정을 나타내는 숫자의 컬렉션이 있다. 가령 컬렉션은 1부터 100까지 interval 중 모든 정수로 구성될 수도 있고, 1부터 100까지 interval 중 모든 짝수로 구성될 수도 있다. 아니면 컬렉션은 수열 내 각 숫자마다 이전 숫자에서 2를 곱하여 계산되는 일련의 숫자로 구성될 수도 있다. 수열은 1부터 시작되고 100에서 또는 그보다 작은 숫자로 끝날 수 있다. 시퀀스 1, 2, 4, 8, 16, 32, 64를 예로 들 수 있다.


수학적 과정은 첫 번째 문자, 마지막으로 계산된 숫자에 대한 한계(최대 또는 최소), 다음에 오는 각 숫자를 계산하는 방법을 특징으로 가진다. 한계는 양의 무한대나 음의 무한대가 가능하다. 등차 수열의 계산 방법은 증가(increment)량을 더하면 되기 때문에 단순하다. 수열에서 이전 숫자에 20을 더해 각 추가 숫자가 계산되는 일련의 숫자를 예로 들 수 있다. 수열은 100부터 시작되고 1 또는 1보다 큰 값으로 끝날 수 있다. 100, 80, 60, 40, 20을 예로 들 수 있다.


Smalltalk-80 시스템에서 Intervals라 불리는 컬렉션의 클래스는 유한 등차 수열로 구성된다. 그 슈퍼클래스 SequenceableCollection과 Collection으로부터 상속된 메시지 외에도 Interval 클래스는 인스턴스를 특징화하는 값으로 접근하고 초기화하는 메시지를 지원한다. Interval의 경우 새 요소를 추가하거나 제거할 수 없다.


Interval의 클래스 프로토콜은 인스턴스 생성을 위한 아래의 메시지로 구성된다.

인스턴스 생성
from: startInteger to: stopInteger startInteger 수부터 시작해 stopInteger로 끝나고, 이전 요소에 1을 더해 다음 요소를 계산하는 Interval 클래스의 인스턴스를 응답한다.
from: startInteger to: stopInteger by: stepInteger startInteger 수부터 시작해 stopInteger로 끝나고, 이전 요소에 stepInteger 를 더해 다음 요소를 계산하는 Interval 클래스의 인스턴스를 응답한다.
Interval 클래스 프로토콜


SequenceableCollections 에 적절한 메시지는 모두 Interval로 전송 가능하다. 또 Interval의 인스턴스 프로토콜은 등차 수열의 increment(incrment)로 접근할 수 있는 메시지를 제공한다.


Number 클래스는 새로운 Intervals를 표현하는 간단한 메시지를 두 개 제공하는데 이는 to: stop과 to: stop by: step이다. 따라서 1부터 10까지 모든 정수의 Interval을 생성하기 위해서는 아래를 평가하거나

Interval from: 1 to: 10


아래를 평가한다.

1 to: 10


100부터 시작해 1로 끝나고 매번 -20을 더하는 Interval을 생성하려면 아래를 평가하거나

Interval from: 100 to: 1 by: -20


아래를 평가한다.

100 to: 1 by: -20


이것은 시퀀스 100, 80, 60, 40, 20이다. Interval은 Intergers로 구성될 필요가 없으므로 10부터 40까지 0.2씩 증가하는 Interval을 생성하려면 아래를 평가하거나

Interval from: 10 to: 40 by: 0.2


아래를 평가한다.

10 to: 40 by: 0.2


그 결과 10, 10.2, 10.4, 10.6, 10.8, 11.0.... 식의 시퀀스가 생성된다.


step의 수치값을 블록으로 대체함으로써 좀 더 일반적인 수열의 사례를 제공할 수도 있음을 주목한다. 새로운 요소가 계산되면 현재 값을 블록으로 value: 메시지의 인자로서 전송하여 이루어질 것이다. size와 do:의 계산 시에는 이러한 계산 방법을 고려해야 할 것이다.


Interval로 전송되는 do: 메시지는 프로그래밍 언어에서 일반적인 for-loop 함수를 제공한다. 아래의 Algol 문은

for i := 10 step 6 until 100 do
    begin
    <statements>
    end


다음과 같이 표현된다.

(10 to: 100 by: 6) do: [ :i | statements ]


Numbers는 예제에서 작성된 것처럼 to:by:do: 메시지에 응답한다. 따라서 반복(iteration)은 괄호 없이 아래와 같이 쓸 수 있다.

10 to: 100 by: 6 do: [ :i | statements ]


OrderedCollection의 여섯 번째 숫자 요소, numbers마다 1을 증가하려면 아래를 평가한다.

6 to: numbers size
    by: 6
    do: [ :index | numbers at: index put: (numbers at: index) + 1 ]


생성된 Interval은 6, 12, 18.... 식으로 숫자의 마지막 요소의 색인까지 지속된다. 컬렉션의 크기가 6(어쩌면 마지막 색인)보다 작으면 어떤 일도 발생하지 않는다. 그 외의 경우 6, 12, 18 식으로 마지막 위치까지 해당하는 요소들이 대체된다.


ArrayedCollection 클래스

앞서 언급했듯이 ArrayedCollection 클래스는 Collection의 서브클래스다. 이는 고정된 범위의 정수를 외부 키로 가진 요소의 컬렉션을 나타낸다. ArrayedCollection은 Smalltalk-80 시스템에 5개의 서브클래스를 가지는데, Array, String, Text, RunArray, ByteArray가 그것들이다.


Array는 어떤 객체든 요소가 될 수 있는 컬렉션이다. 이는 정수를 외부 키로 가지는 요소의 컬렉션을 저장하기 위해 구체적 표현을 제공한다. Arrays의 몇 가지 예를 이미 이번 장에서 제공하였다.


String은 요소가 Characters인 컬렉션이다. Strings의 사용 예는 이번 장과 앞에서 이미 다수 제시한 바 있다. String 클래스는 인스턴스의 비교와 초기화를 위한 추가 프로토콜을 제공한다.


Text는 글꼴 및 강조 변경을 가진 String을 나타낸다. 이는 Smalltalk-80 시스템에서 텍스트로 된 문서를 생성하는 데에 필요한 정보를 저장 시 사용된다. Text의 인스턴스에는 두 개의 인스턴스 변수가 있는데, 하나는 String이고 나머지 하나는 글꼴 및 강조 변경의 인코딩이 저장되는 RunArray의 인스턴스다.


RunArray 클래스는 가능한 색인의 긴 실행(run)에 걸쳐 일관된 경향을 보이는 공간 효율적 데이터 저장공간을 제공한다. 이 클래스는 반복된 요소를 하나씩 저장한 후 각 요소를 요소의 연속된 발생을 나타내는 숫자와 연관시킨다. 예를 들어, String 'He is a good boy.' 를 나타내는 Text가 볼드체로 된 “boy”란 단어와 함께 표시된다고 가정하고, 글꼴에 대한 코드가 1, 볼드체 버전의 코드는 2라고 가정한다. 이후 'He is a good boy.'(17개 Characters로 된 String)와 연관된 Text에 대한 RunArray는 13과 연관된 1, 3과 연관된 2, 1과 연관된 1로 구성된다. 즉 첫 13개 Characters는 글꼴 1로 되어 있고, 다음 3개의 Characters는 글꼴 2, 마지막은 글꼴 1로 되어 있다는 말이다.


ByteArray는 요소가 0부터 255까지 정수로 된 ArrayedCollection 을 나타낸다. ByteArray의 구현은 2 바이트를 16 비트 단어로 저장하는데, 이 클래스는 워드와 더블 워드 접근을 위한 추가 프로토콜을 지원한다. ByteArrays는 Smalltalk-80 시스템에서 시간을 밀리초로 저장하는 데에 사용된다.


String 클래스

앞서 언급한 바와 같이 String에 대한 클래스 프로토콜은 또 다른 String의 복사본을 생성하기 위한 메시지 (fromString: aString) 또는 Stream의 Characters로부터 String을 생성하기 위한 메시지(readFrom: aStream)를 추가한다. 두 번째 메시지에서 주목해야 할 점은 포함된 따옴표 쌍이 읽혀 하나의 요소, 즉 따옴표(quote) 문자로 저장된다는 점이다. 또 String 클래스는 Magnitude 클래스에 명시된 것과 같은 비교 프로토콜을 추가한다. 이러한 메시지들 중 일부는 앞의 SortedCollection 클래스의 설명에서 소개한 바 있다.

비교하기(comparing)
< aString 수신자가 aString 인자 앞에 배열되는지 응답한다. 배열 시퀀스는 대소문자 차이를 무시한 ASCII로 되어 있다.
< = aString 수신자가 aString 인자 앞에 배열되는지, 아니면 aString과 같은지 응답한다. 배열 시퀀스는 대소문자 차이를 무시한 ASCII로 되어 있다.
> aString 수신자가 aString 인자 뒤에 배열되는지 응답한다. 배열 시퀀스는 대소문자 차이를 무시한 ASCII로 되어 있다.
> = aString 수신자가 aString 인자 뒤에 배열되는지, 아니면 aString과 같은지 응답한다. 배열 시퀀스는 대소문자 차이를 무시한 ASCII로 되어 있다.
match: aString 수신자를 #와 *를 포함할 수 있는 패턴처럼 취급한다. aString 인자가 수신자 내 패턴과 일치하는지 응답한다. 매칭은 대소문자 차이를 무시한다. 수신자가 # 문자를 포함하는 곳에서 aString은 어떤 단일 문자든 포함할 수 있다. 수신자가 * 문자를 포함하는 곳에서는 aString이 어떤 문자 시퀀스도 포함 가능하며 어떤 문자도 포함하지 않아도 된다.
sameAs: aString 수신자와 aString 인자와 정밀하게 배열되는지 응답한다. 배열 시퀀스는 대소문자 차이를 무시한 ASCII다.
String 인스턴스 프로토콜


마지막 두 메시지의 사용 예제는 아직 제공하지 않았다.

표현식 결과
'first string' sameAs: 'first string' true
'First String' sameAs: 'first string' true
'First String' = 'first string' false
'#irst string' match: 'first string' true
'*string' match: 'any string' true
'*.st' match: 'filename.st' true
'first string' match: 'first *' false


Strings는 모두 소문자 또는 모두 대문자로 변환이 가능하다. 아니면 Symbol 클래스의 인스턴스로 변환할 수도 있다.

변환하기(converting)
asLowercase 수신자로부터 문자가 모두 소문자로 구성된 String을 응답한다.
asUppercase 수신자로부터 문자가 모두 대문자로 구성된 String을 응답한다.
asSymbol 문자가 수신자의 문자에 해당하는 유일한 Symbol을 응답한다.
String 인스턴스 프로토콜


따라서 아래와 같은 결과를 얻는다.

표현식 결과
'first string' asUppercase 'FIRST STRING'
'First String' asLowercase 'first string'
'First' asSymbol First


Symbol 클래스

Symbols는 유일하도록 보장된 Characters의 배열이다. 따라서 아래는 true를 응답한다.

'a string' asSymbol = = 'a string' asSymbol


Symbol 클래스는 이 목적을 달성하기 위해 그 클래스 프로토콜에 두 가지 인스턴스 생성 메시지를 제공한다.

인스턴스 생성(instance creation)
intern: aString 문자가 aString의 문자에 해당하는 유일한 Symbol을 응답한다.
internCharacter: aCharacter aCharacter 인자에 해당하는 하나로 된 문자의 유일한 Symbol을 응답한다.
Symbol 클래스 프로토콜


뿐만 아니라 Symbols는 Characters의 시퀀스 앞에 # 문자를 붙여 표현할 수도 있다. 예를 들어, #dave는 4개의 Characters로 된 Symbol이다. Symbols는 이러한 접두사를 표기하지 않고 출력한다.


MappedCollection 클래스

MappedCollection 클래스는 Collection의 서브클래스다. 이는 요소가 명명된 컬렉션의 하위컬렉션을 참조하는 접근 매커니즘을 나타낸다. 이러한 매핑은 컬렉션 요소의 재정렬 또는 필터링을 결정할 수 있다. MappedCollection은 “domain”(도메인) 또는 “map”(맵)을 참조한다는 것을 기본 개념으로 가진다. 도메인은 맵에 저장된 외부 키를 통해 간접적으로 접근되는 Collection이다. 맵은 외부 키 집합을 또 다른 외부 키 집합과 연관시키는 Collection이다. 두 번째 키 집합은 도메인 요소로 접근하는 데에 사용할 수 있는 외부 키여야 한다. 따라서 도메인과 맵은 SequenceableCollection의 서브클래스의 인스턴스이거나 Dictionary의 인스턴스여야 한다.


앞서 소개한 Symbols 단어의 Dictionary인 opposites를 예로 들어보자.

키(key)
come go
cold hot
front back
hot cold
push pull
stop start


opposites에서 엔트리의 키 일부에 대해 Symbols이란 동의어의 또 다른 Dictionary를 생성하고 이를 alternates라는 변수명으로 참조한다고 가정하자.

키(key)
cease stop
enter come
scalding hot
shove push


그러면 아래 표현식을 평가함으로써 MappedCollection을 제공할 수 있다.

words  MappedCollection collection: opposites map: alternates


words를 통해 opposites의 요소로 접근할 수 있다. 가령, words at: #cease 표현식의 값은 start가 된다 (예: alternatives에서 cease 키의 값은 stop이고, opposites에서 stop 키의 값은 start이다.). words에 contents 메시지를 전송하면 words에서 opposites의 어떤 부분을 참조하는지 알 수 있다.

words contents


그 결과 start go cold pull 부호를 포함하는 Bag이 생긴다.


at:put: 메시지는 도메인 컬렉션을 간접적으로 변경하는 방법에 해당하는데, 예를 들자면 아래와 같다.

표현식 결과
words at: #scalding cold
words at: #cease start
words at: #cease put: #continue continue
opposites at: #stop continue


클래스간 변환 요약

다양한 컬렉션 유형을 설명하면서 어떤 컬렉션을 다른 어떤 컬렉션으로 변환할 수 있는지 살펴보았다. 간략하게 말하자면, 어떤 컬렉션이든 Bag, Set, OrderedCollection, 또는 SortedCollection으로 변환이 가능하다. Bags와 Sets를 제외한 모든 컬렉션은 Array 또는 MappedCollection으로 변환할 수 있다. Strings와 Symbols는 서로 변환이 가능하지만 어떤 컬렉션도 Interval 또는 LinkedList로 변환될 수는 없다.


Notes