ComputerProgrammingwithGNUSmalltalk:4.3
반복 제어
프로그래밍 언어나 기계를 사용해야 하는 중요한 이유 중 하나를 배울 시간입니다. 기계는 지치거나 실수를 하지 않기 때문에, 여러분이 수백만번 똑같은 일을 하도록 시킬 수도 있으며, 대부분 밀리초 단위로 아주 빠르게 일할 것입니다. 오늘날 컴퓨터의 도움이 없는 분야는 생각할 수도 없습니다. 예를 들어, 군사목적 하드웨어는 빠르고 복잡한 계산을 제한 시간 안에 정확하게 수행해야 합니다. 혹은 천문학 같은 과학분야의 계산은 종이와 연필로 할 수 없는 어마어마한 게산을 수행해야 합니다.
스몰토크는 이러한 목적에서 예외적인 언어가 아닙니다. 이제부터 가장 흔하게 쓰이는 반복 표현을 생성하기 위한 메시지들을 볼 것입니다.
whileTrue:
이 메시지의 일반 구조는 다음과 같습니다.
aBlock whileTrue: anotherBlock
이 메시지는 블록 객체에 보내도록 설계되었습니다. 객체에 메시지를 전달하면, 블록 객체를 평가하여, true일 경우 인자로 전달한 블록을 수행합니다. 이러한 점에서 직접 Boolean 객체를 사용하지 않는 것과, 블록을 전달한다는 것을 제외하면 ifTrue:메시지와 아주 흡사합니다. 그러나 이제부터가 확연히 다른 부분입니다. 만약 메시지를 전달받는 객체가 true로 평가되면 인자 블록을 수행하며, 이후에 이 블록을 한 번 더 제어하는 것입니다. 만약 그때까지도 블록의 실행값이 true라면, 인자 블록을 한 번 더 수행합니다. 이 순환은 메시지를 받는 블록의 실행값이 false가 될 때까지 계속됩니다.
while 반복을 결정되지 않은 반복 indefinite loop 이라고 부르는데, 얼마나 많은 횟수를 반복할지 정하지 않기 때문입니다. 만약 횟수를 안다면, 여러분의 설계를 다시 확인해보기 바랍니다. 왜냐하면 앞으로 배우게 될 루프 기술들이 그런 경우에 더 적합하기 때문입니다.
이 메시지를 더 잘 이해하기에 좋은 예제를 보여드리겠습니다.
"average.st"
"A program which evaluates the sum of the numbers entered to demonstrate the whileTrue: message."
| sum enteredIntegers lastEnteredInteger |
sum := 0.
enteredIntegers := 0.
[ lastEnteredInteger ~= -1 ] whileTrue: [
Transcript cr; show: 'Please enter a number. To exit the program enter -1: '.
lastEnteredInteger := stdin nextLine asInteger.
sum := sum + lastEnteredInteger.
enteredIntegers := enteredIntegers + 1.
Transcript show: 'The average of the numbers entered so far is: ', (sum / enteredIntegers) printString; cr.
]
Please enter a number. To exit the program enter -1: 3
The average of the numbers entered so far is: 3
Please enter a number. To exit the program enter -1: 4
The average of the numbers entered so far is: 7/2
Please enter a number. To exit the program enter -1: 3432
The average of the numbers entered so far is: 3439/3
Please enter a number. To exit the program enter -1: -1
The average of the numbers entered so far is: 1719/2
이 예제는 사용자가 숫자를 입력해주어야 합니다. 그리고 입력했던 값들의 평균값을 계산하여 출력하여 줍니다. 프로그램을 멈추는 방법은 -1 을 입력하는 것입니다. lastEnteredInteger라고 부르는 변수에 수를 입력하면, 매 회마다 -1 인지 아닌지 판단을 합니다.
[ lastEnteredInteger ~= -1 ] whileTrue: [
...
]
연산자 ~= 는 좌변의 객체가 우변의 객체와 다른지를 확인하는 연산자입니다.
다른 입력으로 진행하는 동안 GNU 스몰토크 가상머신은 분수 형태로 평균값을 보여줍니다.
to:do:
이 메시지의 일반 구조는 다음과 같습니다.
aNumber to: anotherNumber do: aBlock
이 구조는 숫자 aNumber로부터 시작하여 anotherNumber가 될 때까지 aBlock 객체를 실행합니다. 반복할 때마다 수는 늘어납니다. aBlock 객체는 블록 인자를 포함하고 있으며, aBlock 표현 안에서 현재 인덱스를 사용할 수 있습니다.
whileTrue: 메시지는 보통 결정되지 않은 반복의 경우에 사용합니다. 대조적으로 to:do:는 반복횟수가 얼마나 필요할지 아는 경우에 사용합니다. 이것이 결정된 반복 definite loop 이라고 불리는 이유입니다.
프로그래머 유경험자들에게:
한정된 반복을 위해 C 기반 언어에서의 for 반복문 대신 스몰토크에서는 이 메시지가 사용된 점을 짐작할 수 있습니다.
이제 예제를 통해 메시지 구조를 확인하여 보겠습니다.
"5_lines.st"
"A program which prints 5 lines to demonstrate the usage of to:do: message."
1 to: 5 do: [:x |
Transcript show: 'This is the ', x printString, '. line.'; cr.
]
This is the 1. line.
This is the 2. line.
This is the 3. line.
This is the 4. line.
This is the 5. line.
이 프로그램은 각각의 인덱스 값을 표시하며 다섯 개의 행을 출력합니다. 블록 인자를 x를 각 반복의 인덱스 값으로 둔 것에 주의하십시오. 만약 블록 객체에 대한 인자를 쓰지 않았다면, 에러가 났을 것입니다.
to:by:do:
때때로 to:do: 메시지의 인덱스를 하나씩 증가시키고 싶지 않을 때가 있습니다. 이러한 목적으로 대신 호출하는 메시지가 to:by:do: 입니다. 일반 구조는 다음과 같습니다.
aNumber to: anotherNumber by: step do: aBlock
aNumber 객체의 값이 anotherNumber에 다다를 때까지 step으로 정의한 수만큼 증가할 것입니다.예를 들어 위의 예제에서 인덱스를 2씩 증가하여 실행하도록 해보겠습니다. 대신 이번에는 10까지 증가하도록 하여서, 반복이 빨리 끝나지 않도록 하겠습니다.
"tobydo.st"
"A program to demonstrate the usage of to:by:do: message."
1 to: 10 by: 2 do: [:x |
Transcript show: 'This is the ', x printString, '. line.'; cr.
]
This is the 1. line.
This is the 3. line.
This is the 5. line.
This is the 7. line.
This is the 9. line.
출력을 보면 어떤 영향이 있었는지를 알게될 겁니다. 이 메시지는 반대 방향으로 줄어드는 데에도 쓸 수 있습니다.
"tobydo_backwards.st"
"A program to demonstrate the backward capability of to:by:do: message."
5 to: 1 by: -1 do: [:x |
Transcript show: 'Oh my god! I''m counting backwards! This is the ', x printString, '. line!'; cr.
]
Oh my god! I'm counting backwards! This is the 5. line!
Oh my god! I'm counting backwards! This is the 4. line!
Oh my god! I'm counting backwards! This is the 3. line!
Oh my god! I'm counting backwards! This is the 2. line!
Oh my god! I'm counting backwards! This is the 1. line!
이번 장은 이것으로 마칩니다. 다음 장에서는 객체지향 프로그래밍에 대한 개념과 클래스를 만드는 법을 배워보면서 우리의 여행을 지속하겠습니다.