Oct 31, 1994
Due: November 9, 1994
new
message so so that it returns an instance of
Stack that is correctly initialized. (This is trivial.) Explain how it
works, i.e. what's a class and what's an instance, and which objects are
getting which messages. (This is messy.)
Kernel-Exception Handling>Exception class>examples
, and run
some of the examples there.
As an exercise in using exceptions, modify the Stack example to grow the
stack when necessary rather than overflowing it. To do this, include a
handler in the push:
message to handle the array out of bounds
exception. This should double the size of the stack's array and retry the
push:
operation. Also include a handler to handle popping an
empty stack. This handler should raise another exception, namely the
exception for
PoppedEmptyStackSignal
. Demonstrate
that your modified pop
method is working correctly by popping
an empty stack and handling the resulting
PoppedEmptyStackSignal
exception.
In more detail, the idea is that if you pop an empty stack without doing
anything special, you will evaluate store at: top
when
top
is equal to 0.
This will cause the array to raise a subscript out of bounds exception.
Just propagating this to the outside world exposes the internal
representation of the stack (as using an array). Instead, in the interests
of encapsulation it is better to raise a different kind of exception
that describes what happened in the stack's terms. Therefore, we'll define
a new kind of exception, namely a popped empty stack exception.
If you do try to pop an empty stack, the stack should raise this exception.
(This is a characteristic example of how to properly integrate exceptions
with abstract data types.)
To illustrate the new, improved stack, suppose you evaluate the following:
PoppedEmptyStackSignal
to your class stack. Add a class
message initialize
, as follows, and send it to initialize this
variable:
body:
, which takes a block as an argument and is the body of
code to execute; execute
, which actually executes the loop;
and exit
, which exits the loop (perhaps prematurely).
ForLoop should also understand interval:
, which is an instance
of Interval, and gives the bounds. WhileLoop and RepeatLoop should also
understand test:
. For loops expect a block with an argument
for the body; while and repeat loops take a block with no arguments.
For example:
2 4 6
on the transcript. (Note that the loop is
terminated when i=6.)
The only tricky part of this question is implementing exit
.
The easiest way to do this is to save an 'exit block' at the beginning of
the execute
method. This exit block can just be
[^nil]
. If the loop object gets the exit message, it can just
evaluate this block, thus terminating the loop. (It's also possible but
trickier to implement exit
by saving the current context when
starting to execute the loop.)
You can use the ordinary Smalltalk control structures in implementing your new control structures.
clam
is defined for class A and also for
class E. What would happen in Extended Smalltalk if you send the
message clam
to an instance of each of A, B, C, D, and E?
What would happen in CLOS? Explain why.