SmalltalkBestPracticePatterns:7.10

From 흡혈양파의 번역工房
Jump to: navigation, search
7.10 Yourself

Yourself

Cascade(p.183)의 값을 사용할 필요가 있다.

  • 마지막 메시지가 메시지의 수신자를 리턴하지 않을 경우 어떻게 Cascade의 값을 사용하는가?


아마도 스몰토크에서 최고로 혼동을 주는 메서드가 아닐까 싶다. Object를 보면 모든 신규 스몰토커가 우연히 발견하는 내용이 있다:


Object>>yourself
    ^self


혹 프로그래머가 매우 현명하다면 (그리고 Interesting Return Value를 모르고 있다면):

Object>>yourself


무슨 일이 일어나고 있는가?


다수의 요소를 OrdredCollection으로 추가하길 원한다고 가정하자. Collection>>add: anObject는 메시지의 수신자가 아니라 anObject를 리턴하도록 정의되어 있다. Collection을 변수로 할당하길 원한다면:

all := OrderedCollection new
    add: 5;
    add: 7


위의 코드는 모든 값이 7이 되는 결과를 야기할 것이다. 이 문제에 두 가지 해결방법이 있다. 첫 번째는 변수 할당을 괄호에 넣는 것이다:

(all := OrderedCollection new)
    add: 5;
    add: 7


  • Cascade의 값이 필요한데 마지막 메시지가 수신자를 리턴하지 않는 경우, "yourself" 메시지를 Cascade 앞에 덧붙여라.


따라서 우리 예제는 아래와 같이 변한다:

all := OrderedCollection new
    add: 5;
    add: 7;
    yourself


"yourself"를 전송하면 수신자, OrderedCollection의 새 인스턴스를 리턴한다. 변수로 할당되는 것은 바로 이 객체이다.


어떤 사람들은 "yourself"에 방어적인 자세를 취하여 그들이 작성하는 모든 Cascade마다 덧붙이곤 한다. 제발 그러지 말길 바란다. "yourself"는 당신이 메시지를 전송한 결과가 아니라 사용된 수신자의 값을 원하고 있음을 독자에게 전달하기 위해 존재한다. Cascade의 값을 사용하고 있지 않다면 "yourself"를 사용하지 말라. 예를 들어, Cascade의 값을 변수로 할당하거나 메서드의 값으로서 리턴하길 원하지 않는다면 "yourself"를 Point>>printOn:에서 사용하지 않을 것이다.

Point>>printOn: aStream
    aStream
        print: self x;
        nextPut: $@;
        print: self y


이를 작성하고 나니 괄호에 넣은 형태보다 Cascades를 선호하는 이유를 정확히 모르겠다. 아마도 괄호로 메서드를 파싱하는 것과 괄호 없이 파싱하는 것 사이에는 심리적인 차이가 크기 때문일지도 모른다. 괄호의 사용을 피했을 때 명확하게 읽히는 메서드가 있다면 그 방법을 택할 것이다.


"yourself"는 #inject:into:와 함께 사용되기도 한다. 부모의 컬렉션에 대한 모든 자녀들을 Set에 집어넣길 바란다고 가정하면, 아래와 같이 작성하고 싶을 것이다:

parents
    inject: Set new
    into: [:sum :each | sum addAll: each children]


하지만 #addAll:을 전송한 결과가 수신자가 아니라 argument이기 때문에 (이번 사례에서는 자녀들을 의미) 위의 코드는 작동하지 않을 것이다. 예상대로 작동시키기 위해선 아래와 같이 작성해야 한다:

parents
    inject: Set new
    into: [:sum :each | sum addAll: each children; yourself]


Notes