Logo
  • Home
  • Classes
  • Conveying Computing
  • Exams
  • Fractal Gallery
  • Guides
  • Problem Sets
  • Syllabus

Problem Set 8: From Aazda to aaZda (Part 1)

Turn-in Checklist: There are two parts to this assignment. The first part is due (electronically) before 11:59pm on Tuesday, 22 November. The second part (which will be described in more detail in a separate page) is due at the beginning of class on Monday, 5 December.

Collaboration Policy - Read Carefully

For this assignment, you should work alone, although you should feel free to discuss the problems with other students in the class.

Remember to follow the pledge you read and signed at the beginning of the semester. For this assignment, you may consult any outside resources, including books, papers, web sites and people, you wish except for materials from previous cs1120, cs150, and cs200 courses. If you use resources other than the class materials, lectures and course staff, explain what you used in a comment at the top of your submission or next to the relevant question.

As always, you are strongly encouraged to take advantage of the scheduled help hours and office hours for this course.

Purpose

The main purpose of this assignment is to give students enough experience programming in Java to be well prepared to take cs2110 in the Spring. Part 1 (due Tuesday, 22 November) introduces Java with some exercises and then asks you to extend the interpreter to support mutation. Part 2 (due Monday, 5 December) extends the interpreter to include manifest types and static type checking. In addition to providing experience with Java and more experience with interpreters, this assignment should give you a good understanding of how static type checking works and why it is useful.

Overview

The most important difference between Java and Python (or Scheme) is that Java uses static type checking. All of the language features we have seen so far were designed to increase the expressiveness of a language: although the small initial subset of Scheme we saw in Class 2 is sufficient to express every possible program, adding lists, begin, let, and mutation, to the language makes it easier to express certain programs concisely. Static type checking serves the opposite purpose: it makes a language less expressive.

There are two reasons we might want to reduce the expressiveness of a programming language. The first one is that sometimes it can make the language implementation simpler and more efficient. For example, the memoizing Charme from Problem Set 7 could only be done because Charme did not provide support for mutation and any side effects. Otherwise, it would not be safe to assume the result of applying the same function to the same inputs will always produce the same output.

The other reason for reducing expressiveness is that it can contribute to the goal of preventing programmers from expressing programs that will crash or produce unexpected results when they are executed. Such languages sacrifice expressiveness for the sake of truthiness — increasing the likelihood that a program means what its programmer intends.

A high level of truthiness is important when software is used to control a physical device whose correct and continued function is essential to safety such as software controlling a nuclear power plant (note, however, that Java's license agreement disallows its use for this purpose!), anti-lock brakes, or aircraft avionics. In such cases, it is much better to reduce the expressiveness of your programming language and get more errors when the software is developed, than to get unexpected behaviors when the software is running.

For this assignment, you will modify a provided Java implementation of an interpreter for a language similar to Charme from Problem Set 7 to provide static type checking. The new language is called Aazda, after a kind of Python found on the island of Java.

Getting Started with Java and Eclipse

The tool we will use to create Java programs is the Eclipse Integrated Development Environment (IDE). Eclipse is similar to DrRacket (for Scheme) and IDLE (Python). It provides an editor for editing Java code. Unlike, Scheme and Python, though, the Java programming language is implemented using a compiler, not an interpreter. This means instead of being able to directly evaluate expressions in an interactions window, we need to first compile our program into an executable, and then run that executable.

Eclipse is a huge and extensible platform, with support for lots of different languages and tools. This makes it difficult to get started with, but once you get used to it, it is a powerful development environment.

Download the Eclipse IDE for Java Developers. It is available for Mac OS X, Windows, and Linux (as well as source code to build for other platforms). The download is a zip file containing an eclipse directory. There is nothing to "install", just extract this directory to wherever you want (for example, your Program Files directory in Windows). The program eclipse.exe (Windows) in this directory is the main Eclipse executable. Double-click on the eclipse logo to start running Eclipse.

The first time you run Eclipse, it will ask you to select a workspace. Create a new directory in your cs1120 directory, and select this as your workspace. (If you check the Use this as the default box, it won't ask you again.) Then, you'll see a welcome screen. It includes Samples and Tutorials, or you can click "Workbench" (the arrow icon) to get started right away.

To start a new project, select File | New | Java Project. Enter the name of the project and select Finish (you probably don't need to change any of the other options).

Part 1: Java Warmup

For the first part of this assignment, you will create a new Java Project in Eclipse and get familiar with Java and Eclipse by making and running a simple Java program. This part of the assignment is not directly related to the second part of the assignment where you modify the Aazda interpreter.

Create a new project in Eclipse by selecting File | New | Java Project. Enter Warmup for the project name, and click Finish.

Then, select File | New | Class to create a class for your project. All code in a Java program must be defined in a class. In the Class dialog, enter warmup for the Package name and Warmup for the class name, and check the box for "Which method stubs would you like to create?" for public static void main(String[] arg). Click Finish to create the class.

You should now see a file Warmup.java in your editor window:

package warmup;

public class Warmup {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
The main method which was created as a stub is the method that will be called when the program is executed. So, you can experiment with Java by adding code to the main method. The declaration includes:
  • public — this means the method can be called by any code (similarly, the Warmup class is also public. Java allows programmers to control the visibility of classes, methods, and variables. For example, if a method is declared using private instead of public, it can only be used by code in the same class where the method is defined.
  • static — this means the method does not have a this object. Methods that do not have the static qualified must be invoked on objects of the class.
  • void — this means that the method has no return value. (Analogous to (void) in Scheme, it produces no output value.)
  • main(String[] args) — this means the name of the method is main, and it takes one parameter named args, with type String [] (that is, an array of String objects).
The generated file also contains two types of comments. Everything between /* and the closing */ is a comment. Everything from // to the end of the line is a comment (like ; in Scheme). You can delete the
	
	// TODO Auto-generated method stub
line and replace it with your code.

You can try running your program (which won't do anything yet) by selecting Run | Run (or Ctrl-F11). The first time you do this you should see a Run As dialog. Select Java Application (the other choice, Java Applet, is used for Java programs that run inside web browsers). Then, you will see a dialog showing a list of the classes that provide static main methods. Select Warmup (which should be the only class listed there).

When it runs, you should see a Console window at the bottom of your workbench. You won't see anything there yet, since the main method is empty, but as you modify the code for the exercises will see the output there when your program runs.

Problem 1. Modify the main method to print out a welcome message.
To print the message, you can use the println method:
    public void println(String x)
provided by the java.io.PrintStream class. Note that unlike main above, this method is not declared using static! That means, it must be invoked on an Object. Try using just, println("Hello"); in Eclipse to see what happens.

There is a built-in PrintStream object that corresponds to the visible stream the user sees. It is called System.out. So, to print a message to the output console, you need to do something like:

   System.out.println("Printing in Java is much harder than in Scheme or Python!");
Problem 2. Define a static factorial method that takes one int (an integer number) as its input, and outputs an int that is the factorial of the input. Modify the main method to use the factorial method you defined to print out the values the factorial for inputs 1 to 20. (See the hint below if your results appear to be correct until 12, but wrong after. It is not necessary to produce correct results above factorial(12).)

Try this yourself first, but if you are stuck use the hints below.

Declaration of factorial method:

public static int factorial(int n) { // YOUR CODE HERE }

Test code in main:

public static void main(String[] args) {
   for (int i = 1; i < 20; i++) {
      System.out.println("factorial(" + i + ") = " + factorial(i));
   }
}

Why are the results wrong after factorial(12)!!?

Unlike in Scheme and Python where numbers are represented in a complex way to be able to hold very large values, in Java the int type is a fixed 32-bit value. It can only hold a fixed range of values (from -2147483648 to 2147483647). If the result exceeds 2147483648, Java just wraps around to the negative numbers without producing any error. So, the value of 2147483647 + 1 in Java is -2147483648.

Lists in Java

Java provides several different ways for managing collections, but nothing that is very similar to Scheme or Python lists. The closest thing in Java to a mutable list is the ArrayList<E> class. To use the ArrayList class, you need to include:

   import java.util.ArrayList;
near the beginning of your Java file (if there is a package statement, it needs to be after that).

Because of explicit static typing in Java, we cannot have lists where the elements can be any type, as we do in Scheme and Java. Instead, we need to explicitly declare the type of each list element as a type parameter to the ArrayList. For example, ArrayList<String> denotes a list where each element is a String. The most general list is ArrayList<Object> where each element is an Object. All object classes in Java are subtypes of Object, so this is a list that can contain elements of any object type. But, not everything in Java is an object (for example, an int number is not an object), so the list elements still cannot be any value.

The ArrayList class provides a constructor for creating an empty list:

    ArrayList<String> slist = new ArrayList<String>();
The add(Element Type) method appends to an ArrayList:
    slist.add("first");
    slist.add("second");
    slist.add(3); // Compile-time type error: only String elements may be added to an ArrayList<String>
The get(int index) method is similar to slist[index] in Python:
    String first = slist.get(0); // gets first element of list
    String second = slist.get(1);
    String missing = slist.get(3); // Run-time error: no element at index 3
The set(int index, element) method is similar slist[index] = element in Python:
    slist.set(0, "primul");
    slist.set(1, "ikinci");
    slist.set(2, "terceiro"); // Run-time error: can only use set to update existing elements
The size() method returns the number of elements in the list:
    int elements = slist.size();

Problem 3. Define a static listReverse method that takes as input an ArrayList<Object> and reverses the order of the elements in that list (analogous to the mlist-reverse! procedure we defined in Scheme and Python). Your method should not return anything (return type is void), but should modify the input list.

Here is some code for testing your listReverse method:
	ArrayList<Object> a = new ArrayList<Object>();
	a.add("one");
	a.add("two");
	a.add("three");
	listReverse(a);
	System.out.println("After a = " + a);
Note that we can put a String object in our ArrayList<Object> since String is a subtype of Object. If S is a subtype of T we can use a value of type S anywhere a value of type T is expected.

Problem 4. Answer this question by adding a comment to the bottom of Warmup.java with your answers.
  1. Is ArrayList<String> a subtype of ArrayList<Object>? You should be able to answer this question empirically by seeing what the Java compiler does in different situations.
  2. Are you happy with the answer? (Hint: will the listReverse procedure you defined work on all lists, like the Python version?)
  3. As a bonus, why do you think Java has the typing rule it does?

Modifying Aazda

For the rest of this assignment, you will modify the Aazda interpreter implemenetation we provide to implement some additional functionality and add static type checking. For Part 1 (due on Tuesday, 22 November), you modify the interpreter to add support for mutation (including the begin special form). For Part 2 (due on Monday, 5 December, the last day of class), you modify the interpreter to add static type checking.

Download: Download ps8.zip to your machine. You do not need to extract the zip file (but instead will import it into Eclipse, following the directions below). This is a Java implementation of an interpreter for a Scheme-like language, that follows closely the design of the Python Charme interpreter from Problem Set 7. The zip file contains a directory containing several Java files that implement the initial Aazda interpreter.
For the questions in this assignment, you will modify several files in the workspace. Please use comments to mark your changes. You should surround each change you make with
/* Modified for Question [N] */
your changed code
/* End Modifications for Question [N]*/

Getting Started With Aazda

To start withing with Aazda, select File | Import in Eclipse. In the import dialog, select General | Existing Projects into Workspace. Then, Select Archive File and use Browse to find the ps8.zip file. Then, select Finish to import the project. After this, you should see the project aazda in your workspace.

You can try running the aazda interpreter by selecting the aazda project and Run | Run (or Ctrl-F11). The first time you do this you should see a Run As dialog. Select Java Application (the other choice, Java Applet, is used for Java programs that run inside web browsers). Then, you will see a dialog showing a list of the classes that provide static main methods. Select REPL for the read-eval-print loop class.

When it runs, you should see a Console window at the bottom of your workbench. The Hiss> prompt is for entering Aazda expressions or definitions to evaluate. Try evaluating a few expressions. You should be able to evaluate anything that you could evaluate in the Charme interpreter from PS7 (although the Aazda interpreter does not implement memoizing, so don't expect to be able to evaluate (fibo 60).)

It is not expected for you to completely understand all of the provided code. It uses many features of Java that students are not expected to encounter even by the end of cs2110. You are, though, encouraged to look at any of the provided code you want, figure out as much as you can about how it works, and to ask questions about anything that you don't understand.

The code is divided into separate .java files for each class. Expand the aazda project, src directory, and aazda package to see the Java files. The provided files include:

  • Tokenizer.java — defines the static tokenize(String s) method that takes as input as String and outputs an ArrayList<String> consisting of the input split into tokens (like tokenize from Charme interpreter).
  • Parser.java — defines the static method parse that takes a String consisting of one more more Aazda definitions or expressions as input and outputs an ArrayList<SExpr> that represents the parsed Aazda expressions.
  • Evaluator.java — this is the core of the evaluator. It defines the meval and mapply methods, as well as methods corresponding to each of the evaluation rules.
  • Environment.java — defines a class for representing Environments.
  • Procedure.java — defines a class for representing compound Procedures.
  • Primitives.java — provides implementations of the primitive procedures.
There are also two classes for representing expressions and values in our interpreter. In the Python Charme interpreter, we just used strings and lists of strings for everything. This has the advantage of keeping the interpreter simpler, but doesn't work well for a typed language like Java. In the Aazda interpreter, we use different types to represent Aazda programs (S-expressions) and values (the results of evaluating Aazda expression):
  • SExpr.java — defines the SExpr class for representing S-expressions. An S-expression is either an atom, which is a String, or a list of S-expressions (an ArrayList<SExpr>).
  • SVal.java — defines the SVal class for representing values in Aazda. An SVal can be a Boolean (boolean), number (int), String, Procedure, or ConsCell. There is also a special void value for representing no value. The SVal class provides constructors for representing different types of values in Aazda programs, and for checking if a value is of a particular type (e.g., isInteger() returns a boolean that is true if an only if the value is a number), and for getting the actual value (e.g., getProcedure() returns a Procedure for a value that is a procedure, but otherwise produces an error if the value is not a procedure).
Examine the provided code to understand how the interpreter works. You should be able to map most things in the Aazda interpreter to familiar procedures from the Charme interpreter (and vice versa).

Adding Mutation

All of the changes you need to make for Problems 5 and 6 should be in Evaluator.java and Environment.java.

First, add set! to the Aazda interpreter. Note the set! must be a special form since the first operand is not evaluated normally: instead of obtaining its value, we need to use it to identify the place to update. It would be a good idea to make sure you understand how definitions are evaluated before implementing set!.

The Environment class uses HashMap<String, SVal> to represent a frame. A HashMap is similar to a Python dictionary (except that the key and value types must be specified explicitly). The put(key, value) method provides a way to add or update the value associated with a key in the HashMap.

Problem 5. Modify the aazda interpreter to add the assignment special form, set!. It should behave like set! in Scheme. (Hint: make sure you understand the lookupVariable(String) method in the Environment class.)
After defining set!, you should see interactions like:
Hiss> (define a 3)
Hiss> (set! a (+ a 1))
Hiss> a
4
Also, make sure you assignment still works when the variable is defined in a parent environment instead of the current execution environment:
Hiss> (define update-a (lambda () (set! a (+ a 1))))
Hiss> (update-a)
Hiss> a
5
Problem 6. Modify the aazda interpreter to add the begin special form. It should behave like begin in Scheme.
Test your begin with some simple expressions, and then on the update-counter! procedure as defined below (from Chapter 9):
Hiss> (define counter 0)
Hiss> (define update-counter! (lambda () (begin (set! counter (+ 1 counter)) counter)))
Hiss> (update-counter!)
1
Hiss> (update-counter!)
2

End of Part 1. You should submit your Warmup.java file and the modified Evaluator.java (including your answer to Problem 1) and Environment.java files before 11:59pm on Tuesday, 22 November using the on-line submission service: https://church.cs.virginia.edu/cs1120/ps8j-part1.html.

Part 2 will be posted separately and due on 5 December.

This assignment was created for cs1120 Fall 2011 by David Evans. The original Aazda interpreter was written by Ivan Alagenchev and Jonathan Burket, and this assignment was tested by Peter Chapman.
Print Friendly Print Get a PDF version of this webpage PDF

4 Responses to “Problem Set 8: From Aazda to aaZda (Part 1)”

  1. cls2be says:
    18 November 2011 at 11:24 am

    Professor Evans,

    I finished the problem set and was trying to submit. However, when I clicked the submission link it was broken. It returned the error “URL not found on server”.

    Log in to Reply
    • David Evans says:
      18 November 2011 at 2:36 pm

      Sorry, it wasn’t up yet! It is up now. There are no test cases for this assignment, but use the form at https://church.cs.virginia.edu/cs1120/ps8j-part1.html to submit your code.

      Log in to Reply
  2. Kevin Liu says:
    22 November 2011 at 12:55 am

    I’m sorry, I don’t really understand…So do we need to include all the code that we wrote for Warmup.java into the code for Evaluator.java?

    Log in to Reply
    • David Evans says:
      22 November 2011 at 7:10 am

      No, this is a mistake (I think you mean the part where it says problems 2 and 3 should modify Evaluator.java and Environment.java). You should keep Warmup.java as it is, and just submit that as a separate file. Sorry for the confusion.

      Log in to Reply

Leave a Reply Cancel reply

You must be logged in to post a comment.

cs1120 | RSS | Comments RSS | Book | BA CS Major | Using These Materials | Login | Admin | Powered by Wordpress