CSE 341 - Homework 7 - Smalltalk Part II

Due: Nov 15, 10pm.

10 points total (5 points per question)

  1. For this question start with the Stack class you defined for HW 6 (or use the sample solution if you prefer). Define a subclass of Stack, called FilteredStack. FilteredStack should have two methods: setsize:filter: and push:. The setsize:filter: method takes two parameters: the initial size of the stack (as with the class Stack), and a block for the filter. The block should take one argument and return true or false. The push: method should check whether the filter returns true when applied to the argument; if so, it should be pushed onto the stack. For example, after executing the following positives should just contain 10 (the 0 and -3 get discarded).
       | positives |
    positives := FilteredStack new setsize: 10 filter: [:x | x>0].
    positives push: 10.
    positives push: 0.
    positives push: -3.
    
    Or as another example, after executing this code the stack should just hold 'clam' and 'squid'.
       | fishfree |
    fishfree := FilteredStack new 
        setsize: 10 
        filter: [:x | (x includesSubString: 'fish') not].
    
    fishfree pushAll: #('one fish' 'two fish' 'clam' 
    'red fish' 'blue fish' 'squid').
    

    Define another test method for FilteredStack that demonstrates that it works correctly as well. Your test method should create at least two stacks, with different filters.

    For full credit, your FilteredStack class may not directly reference Stack's instance variables (top and store). Instead, it must only send messages to self or super to access the stack's state (stored in top and store). Further, FilteredStack can only define the two methods setsize:filter: and push:. However, FilteredStack should have its own instance variable to hold the block (called say filter).

    The idea with these restrictions on what gets full credit is first, that the code will be written in better style; and second, you will use self and super, and understand how they work. For example, the push: method in FilteredStack should use super to get at the push: method inherited from Stack. And pushAll:, inherited from Stack, should still end up invoking the version of push: redefined in FilteredStack.

    Write a "test" method in the class FilteredStack that that comprehensively tests it. Make this a class method rather than an instance method (just select the 'class' button on the browser to do this). Your method should include (in a comment) an expression to run it, for example

    "FilteredStack test"
    This will make it easy to run it as needed. The test method should write out tests to the transcript.
  2. Adding Dynamic Scoping to Smalltalk. Like most other modern languages, Smalltalk is lexically scoped. A number of older languages, for example the original version of Lisp, were instead dynamically scoped. (See the 341 glossary for definitions of static and dynamic scoping.) It can still be useful to provide the option of dynamic scoping in a modern language, even though the default mechanism is lexical scoping. For example, suppose you have a variable debugging. Suppose also you want to set debugging to true while evaluating a piece of code, and then reset it to its old value afterwards. You could pass debugging as a parameter through all calls in your program, but this is clearly inconvenient. Or you could make it be a global variable, set it to true, and then restore its old value after the computation is done -- but that won't work correctly if there are multiple processes with different values for debugging; and also, if the computation is interrupted somehow, the old value won't be restored.

    Dynamic scoping provides a nice solution for handling such situations. For example, you can make debugging be a dynamically scoped variable, and bind it to true before evaluating the piece of code in question. Smalltalk doesn't have dynamic scoping built-in, but (in contrast to nearly all other languages) you can implement it yourself in Smalltalk.

    The article "Defining New Control Structures in Smalltalk-80", by L. Peter Deutsch, which appeared in the August 1981 issue of Byte Magazine, describes how to implement dynamic scoping in Smalltalk. Here is a scanned copy (pdf format).

    Your task for this problem: implement dynamic binding in Smalltalk (using the code in Deutsch's article), along with one additional feature. The additional feature is that if a variable isn't found after looking all the way up the call stack, then check the global symbol table. If it's in the global symbol table, return that value; and otherwise give an error.

    The file DynamicBindingTester.st contains a series of class methods to test dynamic binding, including showing how one binding can shadow another. First evaluate DynamicBindingTester initialize to set things up, then try each of the methods in the test category. (Make sure you understand what they should print, so that you can tell if your code is working.)

    (Hints: the global symbol table is called Smalltalk; it's an instance of the class SystemDictionary. The Deutsch article uses an obsolete method concatenate: to concatenate strings -- use a comma instead. For example, 'sea' , 'weed' evaluates to 'seaweed'.)

Turnin

You should turn in a single "changes" file.

This homework involves changes to several existing classes, as well as new classes. To help cut down on the number of little files you need to turn in, use the change set mechanism, rather than filing out categories of classes or methods. To do this, pick "changes" on the main menu that you get when left-clicking in an open place on the Squeak screen. Then pick "file out current change set". This will write a changes file into your current Squeak directory, containing all of the changes and new classes.

Please just include code for this assignment in the change set. If you have a copy of Squeak with old changes you don't want, you can pick "create new change set" from the changes menu to start a fresh one. Or open a change sorter, and delete the old changes you don't want included.