Computer Science & Engineering 505
Concepts of Programming Languages
Assignment 5 (revised)

Oct 31, 1994
Due: November 9, 1994


  1. Write a simple analog clock in Smalltalk. Use the turtle defined in Assignment 4 to draw the hour and minute hands, and to draw 12 tick marks. You don't need to include the digits. To find the current time evaluate Time now Your clock should keep updating until you interrupt it. To do this, just make a simple loop that repeatedly finds the current time and redraws the hands. You can include a delay statement in the loop to avoid an excessive number of updates: (Delay forSeconds: 10) wait If you want to be fancy, use double buffering to avoid flickering when redrawing the clock (see the code at the end of the graphics examples for an example of using double buffering).

  2. Consider the stack example given in the Smalltalk lecture notes. Override the 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.)

  3. Suppose you were writing the Stack example in SELF instead. Describe the objects you would define. Describe the process of making a new stack, and of sending it the push message. (In particular describe what messages are delegated to what).

  4. Investigate the exception handling mechanism in Smalltalk. Look at the examples in 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:

    | s | s := Stack new. s pop. Here we popped an empty stack, and so it should raise the "popped empty stack" exception. Since there isn't a handler for this, it will just bring up an error notifier. Instead, if we evaluate | s | Stack poppedEmptyStackSignal handle: [:ex | Transcript cr; show: 'tut tut ... cannot pop an empty stack'. ex return] do: [s := Stack new. s pop] then the handler will handle this exception, and print 'tut tut ... cannot pop an empty stack' to the transcript. To define the new signal, add a class variable PoppedEmptyStackSignal to your class stack. Add a class message initialize, as follows, and send it to initialize this variable: initialize PopEmptyStackSignal := NotFoundSignal newSignal notifierString: 'popped an empty stack'; nameClass: self message: #poppedEmptyStackSignal Also add this class message to access it: poppedEmptyStackSignal ^ PoppedEmptyStackSignal You should be able to take it from here.

  5. One of the benefits of using messages and blocks to implement control structures in Smalltalk is that users can define their own control structures. Implement an alternative to the existing iteration control structures that makes explicit objects to represent loops. Define a class Loop, and subclasses ForLoop, WhileLoop, and RepeatLoop (the latter should be like the repeat-until statement in Pascal). Loops should understand 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:

    | a | a := ForLoop new. a interval: (2 to:10 by: 2). a body: [:i | Transcript show: i printString; space. i=6 ifTrue: [a exit]]. a execute. should print 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.

  6. Consider the following class hierarchy in a system with multiple (implementation) inheritance: A /|\ / | \ B C D | / | E | \ / \ / F Suppose that a method 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.