CSC302 2011S Programming Languages

Mid-Semester Examination

Due: 11 p.m., Monday, 11 April 2011


Exam Format

This is a take-home examination. You may use any time or times you deem appropriate to complete the exam, provided you return it to me by the due date.

There are six problems on the exam. Six correct or mostly-correct answers (problems 3-6) or thoughtful answers (problems 1-2) will earn you an A. Five such answers will earn you a B. Four such answers will earn you a C. Three such answers will earn you a D. Fewer than three such answers will earn you an F. Failure to attempt the examination will earn you a zero. At the discretion of the grader, partially correct answers may earn you partial credit.

Read the entire exam before you begin.

I expect that someone who has mastered the material and works at a moderate rate should have little trouble completing the exam in a reasonable amount of time. In particular, this exam is likely to take you about eight hours, depending on how well you've learned the topics and how fast you work.

Academic Honesty

This examination is open book, open notes, open mind, open computer, open Web. However, it is closed person. That means you should not talk to other people about the exam. Other than as restricted by that limitation, you should feel free to use all reasonable resources available to you.

As always, you are expected to turn in your own work. If you find ideas in a book or on the Web, be sure to cite them appropriately. If you use code that you wrote for a previous lab or homework, cite that lab or homework and the other members of your group. If you use code that you found on the course Web site, be sure to cite that code. You need not cite the code provided in the body of the examination.

Although you may use the Web for this exam, you may not post your answers to this examination on the Web. And, in case it's not clear, you may not ask others (in person, via email, via IM, by posting a please help message, or in any other way) to put answers on the Web.

Because different students may be taking the exam at different times, you are not permitted to discuss the exam with anyone until after I have returned it. If you must say something about the exam, you are allowed to say This is among the hardest exams I have ever taken. If you don't start it early, you will have no chance of finishing the exam. You may also summarize these policies. You may not tell other students which problems you've finished. You may not tell other students how long you've spent on the exam.

You must include both of the following statements on the cover sheet of the examination.

  1. I have neither received nor given inappropriate assistance on this examination.
  2. I am not aware of any other students who have given or received inappropriate assistance on this examination.

Please sign and date each statement. Note that the statements must be true; if you are unable to sign either statement, please talk to me at your earliest convenience. You need not reveal the particulars of the dishonesty, simply that it happened. Note also that inappropriate assistance is assistance from (or to) anyone other than Professor Rebelsky (that's me).

Presenting Your Work

You must present your exam to me in two forms: both physically and electronically. That is, you must write all of your answers using the computer, print them out, number the pages, put your name on the top of every page, and hand me the printed copy. You must also submit an electronic copy of your exam. You should create the electronic version by making a tarball of any relevant code and submitting that tarball on Pioneerweb. Failure to name and number the printed pages will lead to a penalty. Failure to turn in both versions may lead to a much worse penalty. Failure to turn in a legible version of the exam is also likely to lead to a penalty.

If your answer relies on provided files but you have not modified the files, you should include them in the tarball but should not include them in the printed copy of the exam.

If your answer relies on libraries you've found elsewhere, please include those libraries in the tarball, along with a Makefile that lets me build your programs.

In many problems, I ask you to write code. Unless I specify otherwise in a problem, you should write working code and include examples that show that you've tested the code.

You should document all code that you write, preferably with six-P style documentation.

Just as you should be careful and precise when you write code and documentation, so should you be careful and precise when you write prose. Please check your spelling and grammar.

I may give partial credit for partially correct answers. I am best able to give such partial credit if you include a clear set of work that shows how you derived your answer. You ensure the best possible grade for yourself by clearly indicating what part of your answer is work and what part is your final answer.

Getting Help

I may not be available at the time you take the exam. If you feel that a question is badly worded or impossible to answer, note the problem you have observed and attempt to reword the question in such a way that it is answerable. You should also feel free to send me electronic mail at any time of day.

I will also reserve time at the start of each class before the exam is due to discuss any general questions you have on the exam.


Problem 1: Choosing a Language for the Problem

Your fictitious classmates, Otto and Olivia Oblivious, say that they have learned ten languages in their career at Grinnell: The three introductory languages (Scheme, C, and Java) and the seven languages we've considered in CSC 302 (Ruby, Io, Prolog, Scala, Erlang, Clojure, and Haskell). And they are correct in one sense: Given a problem specification and a language, they can usually implement a solution in that language.

However, they have failed to embrace upon the most important learning outcome: An ability to reflect on the strengths and weaknesses of each language and its applicability for solving certain kinds of problems.

In the next week, they are going to have to write three programs. They have asked you to select the languages they might use for those four programs and to explain to them why those are good choices.

For each of the following three programming exercises, suggest two languages that would be best to use when implementing the program and give a short (1/4 to 1/3 page, single spaced) explanation of why each of those languages would be particularly appropriate to the problem at hand.

In case that wasn't clear, you should have six parts to your answer: two languages per exercise for three exercises.

Exercise 1: Representing and Evaluating Boolean Expressions

In Otto and Olivia's Theory of Computation course, they are studying Boolean formulae. (After all, 3SAT is an interesting problem from that course.) In order to better study those formulae, they have been asked to do three related programming tasks.

Exercise 2: Solving Puzzles

In Otto and Olivia's Problem Solving course, they get asked to solve a wide variety of problems. Here's one recent problem.

While Otto and Olivia know that they should be able to solve this problem logically, they think that as computer scientists, they should solve all problems by writing programs, so they're going to write a program to find the solution.

Exercise 3: Eavesdropping

In Otto and Olivia's Computer Security class (yeah, they don't have a very diverse schedule, do they?), they are exploring simple statistical analyses of messages (Twitter, email, whatever). Their instructor says that they should model each message using a string that contains XML in the following form.

<message id="____">

Otto and Olivia have to do the following:

Like all good programmers, they have access to any libraries they can find on the Web.

Problem 2: Avoiding Languages

Otto and Olivia read your recommendations and note that they appreciate your thoughtful suggestions. However, being Oblivious, they hadn't really listened to their instructors instructions. Their instructor said I will choose the language in which you implement each problem. However, I know that there are languages that some of you don't like to use. So, you can each choose one language to eliminate from the list of ten.

For each of the three programming exercises again, suggest two languages that would be the most difficult to use for the task and briefly explain (approximately 1/4 page, single spaced) why each of those languages would be difficult for the problem at hand.

Problem 3: Boolean Expressions

Implement the program from Exercise 1, Representing and Evaluating Boolean Expressions, in one of the ten languages (three core, seven from Tate).

Problem 4: Solving Puzzles

Implement the program from Exercise 2, Solving Puzzles, in one of the ten languages (three core, seven from Tate).

You may not use the same language that you used in the previous problem. In addition, if you used a core language (Scheme, C, Java) for the first problem, you may not use a core language for this problem.

Problem 5: Eavesdropping

Implement the program from Exercise 3, Eavesdropping, in one of the ten languages (three core, seven from Tate).

You may not use either of the languages you used in the previous two problems. In addition, if you used a core language (Scheme, C, Java) in one of those two problems, you may not use a core language in this problem.

Problem 6: Dictionaries

As you no doubt have noticed, most modern languages contain a dictionary (aka hash, map, table, etc.) data type. Using the hash table data structure, implement a simple dictionary library for C in which keys and values are both strings. In particular, you should create a dict type and the following operations on that type.

dict dict_new ()
Create a new dictionary.
int dict_add (dict d, char *key, char *value)
Add a key/value pair to the dictionary. If a value previously exists for that key, you should replace it. This operation should take amortized expected constant time. The return value indicates success or failure. (If at all possible, dict_add should succeed. However, there are a few cases (e.g., you you need to malloc or strdup memory and it fails) in which it may be necessary to indicate failue.
char *dict_get (dict d, char *key)
Get the value associated with a key. Return null if there is no value with the given key. This operation should take expected constant time.
void dict_free(dict d)
Free any space allocated to the dictionary.

I will provide some unit tests for the dictionary in the near future. You may also wish to write your own.


Here you will find answers to questions of general interest. Please check here before emailing me your questions!

Problem 1

Problem 2

Problem 3

Problem 4

Problem 5

What do you mean by a generator?
Your program needs some way to request the next message. The generator is a stub that gives back a sample next message each time it is used. (In a real programming environment, we would use the test generator while testing, and then substitute a generator that returns the next value in the real message stream.)

Problem 6

Why does dict_add return an integer? Shouldn't it always succeed?
In an ideal world, it would always succeed. However, dict_add is likely to allocate memory, and sometimes it is not possible to allocate more memory. There are also other possible modes of failure (none of which come to mind right now).
What should dict_new return if it can't create a new dictionary?
That's up to you. Make sure to document your decision.
I need a pointer for this. Would you accept a parameter of dict *?
No. The goal is to hide the underlying pointer from the user, who may be a novice programmer. You can, however, do something like the following.
struct dictionary { ... };
typedef struct dictionary *dict;
What do you mean by expected time?
For many randomized algorithms, you can't predict the exact time it will take. For example, if you always pick a bad pivot in Quicksort, then Quicksort is O(n2) rather than O(nlogn). Expected time is the time the algorithm should take in most cases.
What do you mean by amortized time?
Some algorithms have some large costs (e.g., an O(n) step) that make the worst case step look bad. By we can amortize those costs over multiple calls if they are done rarely. For example, if the O(n) step is done only once every n calls, and the other calls are all O(1), then the algorithm may be said to have amortized constant time.
Can we use the strings passed us directly, or do we have to make copies?
You have to make copies, of course.


You normally give extra credit for errors of spelling and grammar on your exams. Can we get such extra credit for this exam? [2011.03.24].



Early March 2011 [Samuel A. Rebelsky]

  • Started to design exam.

Thursday, 24 March 2011 [Samuel A. Rebelsky]

  • Wrote.
  • Released.
  • Policies based on my standard set of take-home exam policies.
  • Clarified the return value of dict_add after question from a student.

Sunday, 3 April 2011 [Samuel A. Rebelsky]

  • Added some Q&A.

Wednesday, 6 April 2011 [Samuel A. Rebelsky]

  • Updated due date.

Friday, 8 April 2011 [Samuel A. Rebelsky]


Disclaimer: I usually create these pages on the fly, which means that I rarely proofread them and they may contain bad grammar and incorrect details. It also means that I tend to update them regularly (see the history for more details). Feel free to contact me with any suggestions for changes.

This document was generated by Siteweaver on Fri Apr 8 06:28:22 2011.
The source to the document was last modified on Fri Apr 8 06:28:18 2011.
This document may be found at

You may wish to validate this document's HTML ; Valid CSS! ; Creative Commons License

Samuel A. Rebelsky,