Lab 5: Debugging

Due Dates

Because this is also the week of the midterm, this lab is due at noon on Friday for everyone.

Objectives

In this lab, we will focus on debugging. The goal of this lab is to gain experience with the following:

  • Understanding the different types of errors that can arise while programming

  • Developing some debugging strategies to identify and resolve these errors

  • Writing useful test cases that discriminate between a buggy and correct version of a program

Different Types of Errors

When programming, you may encounter three main types of errors:

  1. Syntax errors. These are textual errors that are identified by Python before it attempts to run the program. For example, if you forget a colon after the function definition def foo(), or forget to indent properly, Python will complain that your syntax is incorrect. These errors, while annoying, are typically the easiest to correct.

  2. Runtime errors. When the program begins running, there are some conditions that may unexpectedly arise that Python will complain about. For example, suppose you compute the average of a list speeds in the following definition, found in a file physics.py:

    def meanSpeed(speeds):
        return sum(speeds)/len(speeds)
    

    It is possible that speeds is empty. If so, the computation attempts to illegally divide by zero:

    Traceback (most recent call last):
        File "physics.py", line 29, in meanSpeed
        return sum(speeds)/len(speeds)
    ZeroDivisionError: division by zero
    
  3. Logic errors. Sometimes when we translate an algorithm into code we may introduce mistakes in logic. For example, we may reset a variable to zero, or append a value incorrectly within a conditional, etc. Logic errors are among the hardest bugs to isolate and debug, because even though your program runs just fine, it fails to do what you expect it to do.

Reading error messages. As we investigate our scripts this week, we will want to carefully read the hints that Python gives us. For example, when syntax error messages are printed, they include line numbers. The error is very likely at or before the indicated line number. Fortunately, all modern text editors (like Atom) show us line numbers for the current location.

When runtime errors occur, the Python system often prints a stack trace or traceback. This is a list of lines in the program that are currently being executed. Information about the most recent line appears near the bottom of the trace. Carefully reading the stack trace can give you important clues about what your program was doing when it stopped running.

Using print statements. Logic errors often stem from bad assumptions about the state of the program. To fix them, it is often helpful to get a better view of the program’s variables. The judicious use of print statements can help to isolate sections of the code that lead to unexpected values in state.

To get started on this week’s lab, you should clone the lab05 repository in the usual manner:

git clone https://evolene.cs.williams.edu/cs134-labs/22xyz3/lab05.git

Remember to replace 22xyz3 with your CS username.

Required Tasks

We would like you to fix errors in two of the scripts we’ve included in this week’s repository.

1. Syntax Errors

The script swedishpuzzle.py is riddled with syntax errors. This script is inspired by a Swedish word puzzle game called “Rövarspråket”. Given a string word and letter letter, the rules of “Rövarspråket” ask for a new word which is created as follows:

  • Each consonant in word is doubled and the supplied letter is inserted between (e.g. 'n' becomes 'non' when 'o' is supplied).

  • Pre-existing vowels in word remain untouched.

Ideally, the function convert in swedishpuzzles.py takes a letter and a word as input (both of type string) and returns a new string answer according to the rules of the game. The logic of the included script is sound, but there are many syntax errors that you must fix. As you fix errors, mark each corrected line with a comment, such as “#FIXED,” so we know what you changed. As you get started, you may use the commented out print statements to find out more about the behavior of the program as it executes.

Once you have fixed all the errors, then running the script python3 swedishpuzzle.py should print the following:

convert('ouo', '') returns ''
convert('o', 'stubborn') returns 'sostotubobboborornon'

2. Logic Errors

The script vowelacious.py contains two buggy versions of the function isVowelacious. We call a word vowelacious if it contains three or more consecutive vowels. For example, the word 'vowelacious' is itself vowelacious because of the substring iou. A correct isVowelacious function should take a word (string) as input, and return True if it is vowelacious; else it should return False.

We have given you two incorrect implementations of this function: isVowelaciousBuggy1 and isVowelaciousBuggy2. You must analyze each of these functions to identify the logic errors. We have provided a few debugging print statements (as comments) that you may want to uncomment to see how the state of the variables is changing in each function. You may add as many print statements as you want, but please do not modify the logic of these functions.

In addition to finding the logic errors, you must also complete the following three subtasks:

  • At the top of the file, there are 3 variables: buggy1Vowelacious, buggy1NotVowelacious, and buggy1Bad. Set these strings to be words satisfying the following criteria.

    • buggy1Vowelacious is a Vowelacious word and isVowelaciousBuggy1(buggy1Vowelacious) returns True.

    • buggy1NotVowelacious is a non-Vowelacious word and isVowelaciousBuggy1(buggy1NotVowelacious) returns False.

    • buggy1Bad is a Vowelacious word but isVowelaciousBuggy1(buggy1Bad) returns False.

    In other words, find two inputs for which the function works properly, and then an input for which the function produces a “false negative”.

  • Similarly, set buggy2Vowelacious, buggy2NotVowelacious, and buggy2Bad to strings satisfying the same criteria for the second broken version of our function, isVowelaciousBuggy2:

    • buggy2Vowelacious is a Vowelacious word and isVowelaciousBuggy2(buggy2Vowelacious) returns True.

    • buggy2NotVowelacious is a non-Vowelacious word and isVowelaciousBuggy2(buggy2NotVowelacious) returns False.

    • buggy2Bad is a Vowelacious word but isVowelaciousBuggy2(buggy1Bad) returns False.

  • Fill in the TODO comment in the docstring for both buggy functions to briefly describe the logic error.

  • Finally, complete the isVowelacious function with the correct implementation.

Remember that you can put function calls to test a function directly in the if __name__ == "__main__": block. Sometimes this is preferable for debugging rather than using doctests (or testing interactively) as it allows you to comment out test cases, and proceed one at a time.

Submitting Your Work and Grading Guidelines

  1. As you finish identifying and removing bugs in each script, do not forget to add, commit, and push your work to the server.

  2. Update your README.md to record an collaborations.

  3. As always, the file GradeSheet.txt in your lab05 repository goes over the grading guidelines and documents our expectations.