ComputerProgrammingwithGNUSmalltalk:3.1
객체와 메시지
객체object는 프로그램에서 하나의 대상을 나타내는 단위입니다. 객체는 인스턴스 변수instance variable 라고 하는 객체 상태를 가지고 있으며, 외부 (사용자나 다른 객체) 로부터 오는 메시지에 어떻게 응답할지 정의한 선언들, 즉 메서드method 를 가지고 있습니다. 메시지를 작성하고, 객체와 인스턴스, 그리고 메서드를 정의하는 데에는 일관된 문법 규칙이 쓰입니다. 몇 가지 정의를 작성했지만 아마도 여러분 대부분은 제대로 이해하지 못했을 것입니다. 만약 그러하다면, 윗 문단을 한 번 더 읽고 진행하기 바랍니다. 왜냐하면 처음 접하는 경우라면 이러한 개념을 갖기가 어렵기 때문입니다. 앞으로 나올 예제들은 이러한 개념을 확실하게 해줄 것입니다.
이제 몇몇 예제 객체와 메시지 표현들을 보도록 하겠습니다. 먼저 수식표현은 어떨까요? 아래의 코드를 GNU 스몰토크 인터프리터에 입력하고 키보드에서 <Enter>키를 눌러보십시오.
3 + 4
공백이 있는지 여부는 그리 중요하지 않습니다. 원하는 만큼 긴 공백을 넣을 수도 있고, 공백을 안 넣을 수도 있습니다. 덧셈 부호 앞뒤로 개행문자를 넣을 수도 있습니다. 이제부터 공백이라 불리는 개념을 설명하겠습니다.
공백white space은 빈 칸, 탭, 개행문자에 주어진 이름입니다. 모두 다 공백이라 부르는데, 당연히 보이기 않기 때문에 그렇게 부릅니다. 보통 공백은 프로그래밍 언어에서 의미가 있는 부분이 아니기 때문에, 컴파일러와 인터프리터들은 문자열 안에 들어있는 경우가 아니라면 공백을 무시합니다.
이제 수학적 표현으로 돌아와봅시다. 여기서 주 객체는 3입니다. 우리가 메시지를 보낼 객체는 3 이며, 메시지를 받기 때문에 3을 리시버 receiver 라고 부릅니다. + 4 라는 문자들은 메시지가 되어 리시버 3에게 날아갑니다. 3에 보낸 메시지는 다음과 같습니다. "내가 보낸 숫자와 너 자신을 더한 후에 결과를 반환하라."
셀렉터 (selector) 와 인자 (argument)
이제는 위에서 보낸 메시지를 자세히 보도록 하겠습니다. 실제 이 메시지에서는 두 부분이 있습니다. 하나는 셀렉터이며 + 문자입니다. 또 다른 부분은 인자로 객체인 4 입니다. 여러분은 메시지의 인자 부분을 제거하는 것으로 셀렉터를 얻을 수 있습니다 (이에 대한 예제는 나중에 보여드리겠습니다).
셀렉터는 메시지에 어떻게 응답할지 결정하도록, 객체를 돕는 체계를 형성합니다. 예를 들어, 여기 + 셀렉터는 실제로 객체 3 안에 정의되어 있으며, 3은 이 메시지를 받았을 때 어떻게 할지 알고 있습니다.
인자argument는 객체가 응답을 실행하는 동안 사용해야 하는 추가적인 정보입니다. 객체는 이들 정보를 응답을 실행할 때 어떻게 사용할지를 알고 있습니다. 객체가 이 모든 것을 어떻게 아는지는 우리가 원하는 객체를 어떻게 정의할 수 있는지를 알아보면서 보게될 것입니다. 주의할 점은 메시지가 꼭 인자를 가질 필요는 없다는 점입니다. 실제로 다음의 메시지는 아무런 인자를 보내지 않습니다. 여기를 보십시오.
'Hello World!' size
여기 문자열 객체 'Hello World!'와 메시지 size가 있습니다. 이 메시지는 문자열 객체에게 갖고 있는 문자열의 길이, 즉 얼마나 많은 문자들을 가지고 있는지를 반환하라는 내용입니다. 보시다시피 size 메시지는 따로 인자가 필요하지 않기 때문에, 어떤 인자도 가지고 있지 않습니다. 즉 메시지가 모든 정보를 가지고 있으며, 다른 말로는 질문 속에 답이 있는 것입니다. 좋습니다. 이 정도면 설명이 충분하겠죠?
바로 이전의 예제를 보고 메시지 형식에 대해 말해보겠습니다. 컴퓨터는 오로지 1과 0을 이해하고 있다고 말 했습니다. 따라서 숫자 3은 실제로 컴퓨터 메모리 안에서 다음과 같이 2진수로 기록되어 있습니다[1].
00000011
우리는 8자리로 표시하는 1바이트의 메모리에 이와 같이 기록하였습니다. 이제 위에서 주어진 정보를 다음 코드를 입력해봅시다.
3 bitAt: 3 put: 1
이 표현은 객체 숫자 3과 bitAt: 3 put: 1 이라는 메시지를 가지고 있습니다. 이 메시지에는 bitAt: put: 이라는 셀렉터와 3 과 1 이라는 인자를 가지고 있습니다. 어떻게 셀렉터의 이름을 얻는지 기억하고 계십니까? 인자를 제거한 메시지의 나머지 부분이 셀렉터라고 하였습니다.
이 메시지는 정수 객체 3에게 세번째 비트 값을 1로 대체하라고 말하고 있습니다. 비트 자릿수는 오른쪽부터 왼쪽으로 세어 나갑니다. 3의 세번째 비트는 0입니다. 그러나 이제는 1 입니다. 따라서 우리는
00000111
위와 같이 십진수로 7에 해당하는 값을 얻을 수 있습니다. 메시지를 보낸 후, 수식 표현을 평가해서 터미널에 출력합니다.
단항 메시지, 이항 메시지 그리고 키워드 메시지
메시지 형식은 3가지가 있습니다. 각 형식 간 차이점은 셀렉터, 인자, 그리고 우선순위와 관련한 것입니다. 우선순위가 무엇이냐고요? 그건 조금 있다가 설명드리겠습니다.
단항 메시지unary message는 인자가 없는 메시지입니다. 단항이라 불리는 것은 결과적으로 표현식이 객체 하나만을 포함하고 있기 때문입니다. 단항 메시지의 예를 보여드리겠습니다.
'Hello World!' size
보시다시피 여기엔 인자가 없으며, 전체 표현은 문자열 객체 ‘Hello World!’ 만을 포함하고 있습니다.
이항 메시지binary message는 하나의 인자를 가진 메시지입니다. 이항 메시지의 다른 특성은, 셀렉터에는 알파벳이나 숫자가 아닌 문자로 2자까지 가능합니다. 예를 들어, 다음의 이항 메시지를 보십시오.
3 + 4
여기서 + 는 셀렉터이며, 4는 셀렉터에 대한 인자입니다. 표현은 3과 4, 두 개의 객체를 포함하고 있습니다. + 는 한 개의 문자이며 알파벳이나 숫자가 아닙니다. 따라서 이항 메시지로서 요구사항을 맞출 수 있습니다.
마지막으로 키워드 메시지keyword message는 셀렉터의 인자를 하나 이상 갖는 메시지입니다. 인자는 알파벳, 숫자로 이루어져 있습니다. 셀렉터의 뒤에 콜론을 붙인 후, 인자가 필요하다는 것을 표시하여야 합니다. 이항 메시지 표현의 예는 다음과 같습니다.
3 bitAt: 3 put: 1
여기서 셀렉터는 bitAt:put:이며 3과 1이 인자입니다. 전체 표현은 세 개의 객체를 포함하고 있지만, 한 개 혹은 그 이상의 객체를 가질 수 있습니다.
메시지 형식에서 셀렉터와 인자에 대해 얘기하였지만, 아직 우선순위에 대해서는 설명하지 않았습니다. 우선순위는 하나의 표현에 많은 메시지가 있을 때, 어떤 것을 먼저 실행할지 결정하는 개념입니다. 그러한 표현을 상상하기 어렵다면, 걱정하지 마십시오. 여기에 예제가 있습니다.
3 + 5 bitAt: 3 put: 1 printNl
보시다시피, 여기엔 세 개의 메시지가 있습니다. +, bitAt:put: 그리고 printNl까지. 여기서 어떤 것을 제일 먼저 수행해야 할까요? 우선순위 규칙에 따라 해보지요.
스몰토크에는 메시지 우선순위에 대한 몇 가지 기본 규칙이 있습니다.
- 단일항 메시지는 가장 먼저 실행됩니다.
- 이항 메시지는 두번째로 실행됩니다.
- 키워드 메시지는 마지막에 실행됩니다.
- 만약 괄호 안에 표현이 있으면, 제일 먼저, 그것부터 실행됩니다.
- 만약 같은 선행 조건을 가지고 있는 메시지가 있다면, 왼쪽부터 오른쪽순으로 메시지가 각각 실행됩니다.
이제 이 우선순위 조건을 설명할 두 가지 예제를 보여드리겠습니다. 첫 번째 예는 위에 제시한 예입니다.
3 + 5 bitAt: 3 put: 1 printNl
12
이제 왜 1과 12를 출력하였는지 볼 시간입니다. 이 표현식에서 인터프리터가 먼저 만나는 것은 단항 메시지 printNl 입니다. 그리고 바로 앞의 객체로 이 명령을 수행합니다. 이 경우 1입니다. 따라서 처음 출력은 1 입니다. 그리고 이 표현식은 1을 확인하여 그 자체를 답합니다. 이제 표현식은 다음과 같이 정리할 수 있습니다.
3 + 5 bitAt: 3 put: 1
이제 두 개의 메시지가 있습니다. 하나는 +로 이항 메시지이며, 다른 하나는 bitAt:put:으로 키워드 메시지입니다. 규칙에 따라 위 표현식은 8이라는 결과를 내놓는 이항 메시지를 먼저 실행합니다. 따라서 표현식은 다음과 같이 나타낼 수 있습니다.
8 bitAt: 3 put: 1
이제 키워드 메시지 하나만 남았습니다. 이 메시지는 정수 12에 대해 확인할 것입니다 (여러분이 직접 종이에 적어서 계산해보시길 바랍니다). 마지막으로 인터프리터가 터미널 상에 객체를 출력할 것입니다.
이제 두 번째 예제를 보도록 하겠습니다.
(3 + 5 bitAt: 3 put: 1) printNl
12
이전 예제와 한 가지 다른 점은 printNl 메시지 앞의 내용을 괄호로 묶어준 것입니다. 그러나 결과는 아주 다릅니다. 왜냐하면 괄호 안의 메시지를 먼저 실행한 후, printNl 메시지를 전달하기 때문입니다.
Notes
- ↑ 실은 정수를 메모리에 저장하는 형식은 성능 상의 문제로 더 복잡합니다. 그러나 여기서는 예를 위해 이렇게 가정한 것입니다.