Debugging
tutorial processing debugging- Debugging with Your Brain
- Processing editor
- Compiler Errors
- Runtime Errors
- Logic Errors
- Researching Errors
- Print Statements
- Debugging with the Debugger
- Work in Small Pieces
- Other Debugging Tips
- Get Help
Youâve now learned about the fundamentals of coding in Processing, and now youâre writing your own code. Thatâs great!
No matter where you are in your coding journey, whether youâre just starting out or if youâve been coding for years, youâre going to find yourself in situations where your code is behaving differently from what you expected. Thatâs totally normal! This happens to every single programmer, every single time they write code.
This tutorial introduces some approaches and tools for understanding and fixing your code, which is also called debugging.
Debugging with Your Brain
The first (and best) debugging tool is something you already have: your brain!
It can be really frustrating when you encounter a situation where your code is behaving differently from what you expected. But instead of throwing the computer out the window, try these approaches.
Be specific. What were you expecting to happen? What exactly happened instead? Donât say something like âI wanted to draw a flower but itâs not workingâ. Instead, say something like âI expected a red circle to show in the upper-left corner, but instead I only see half a circle at the top.â Being more specific helps you narrow down exactly whatâs happening, and later itâll help you talk to other people about your code.
Read your code line by line. This is one of the most important skills you need to learn to be a good coder. Double check that the code you wrote is the code you meant to write, just like youâd proofread anything you were writing. Check for issues like spelling, capitalization and that youâre using the right keywords and symbols (see compiler errors below).
Use a piece of paper and a pencil to write down the value of each variable, and to draw stuff to the âscreenâ as you read through your code. Donât assume you know what the code does, and take it one line at a time. Reading it out loud can help.
Processing editor
The Processing editor lets you write and run your code, and it comes with a few handy tools for debugging as well.
As you write your code, if it has a compiler error (more on that in the next section), your first clue will be a red underline underneath any code that your computer canât understand.
You can click on these underlined words for more information about why Processing is confused.
(This code forgot the ()
after draw
.)
The second tool is the Console that displays at the bottom of the editor. When you run your code, if it contains a syntax error or a runtime error, the error message will show up in the console.
(This code forgot to give message
a value.)
Remember, getting errors is a normal part of coding! Next, letâs talk about different types of errors and how to figure them out.
Compiler Errors
Unlike human languages, code doesnât leave a lot of room for mistakes. If you spell something wrong in a human language, most people will probably still understand you. But computers arenât that smart.
Syntax is a fancy word for the keywords and symbols you can use in code. If your code only uses valid keywords and symbols in an understandable order (in other words, if your syntax is valid), then the computer will be able to understand your code. But if you use a keyword or a symbol that the computer doesnât recognize (in other words, if your syntax is not valid), then the computer will instead give you an error.
This type of error is called a compiler error or a syntax error. Compiler errors include issues like forgotten semicolons or misspelled variables, as well as violating the rules of Processing, like trying to store a String
value in an int
variable. When you have a compiler error, Processing canât run your code, because it doesnât understand what youâre telling it to do.
Hereâs an example that contains a compiler error.
void setup() {
size(300, 300);
}
void draw {
background(50);
}
Type this code into your Processing editor, and notice a couple things:
- The Processing editor shows a red line under the
void draw {
line. - If you click the red line, a message saying
Missing a semicolon ";"
appears. - If you try to run the code by pressing the play button, the editor shows a red message saying
unexpected token: draw
.
You canât run the code, so no window pops up, because a compiler error prevents the computer from understanding what you want it to do.
For this specific example, the error is happening because this code is missing the parentheses ()
after draw
. It should be this instead:
void setup() {
size(300, 300);
}
void draw() {
background(50);
}
Learning all of the syntax rules about a language can be pretty overwhelming when you first start coding, but over time you learn why the rules exist, which makes them easier to remember. (For example, you need ()
here because some functions take arguments, which go inside the parentheses!)
Runtime Errors
Even if your syntax is valid, you can still encounter errors when you run your code. These runtime errors usually happen when your code tries to do something that the computer doesnât understand. Hereâs an example:
String message;
void setup() {
size(300, 100);
textSize(36);
}
void draw() {
background(64);
text(message, 20, 50);
}
This program defines a message
variable, and uses the text()
function to draw that message to the screen. Type this into the Processing editor, and notice that you donât see any compiler errors, because this is all valid syntax. But when you run the program, a window pops up, but no text is displayed! And you get an error:
The Processing editor highlights the text(message, 20, 50);
line and shows NullPointerException
in the console.
NullPointerException
is one of the most common runtime errors, and itâs caused by using a variable that you havenât given a value. In this case, the code forgot to give the message
variable a value.
You could fix this error by making sure the variable is defined before you use it:
String message;
void setup() {
size(300, 100);
textSize(36);
message = "Happy Coding";
}
void draw() {
background(64);
text(message, 20, 60);
}
There are many other types of runtime errors, but the general process for understanding them is the same: look at the line highlighted in the editor to find out which line of code triggered the error, and look in the console to see what error was triggered.
Logic Errors
In addition to syntax and runtime errors, thereâs another type of error thatâs not really an error at all. We have a name for the situation when your code runs without encountering a syntax or runtime error, but still does something different from what you expected. We call this a logic error.
Logic errors are probably the most common type of error, and theyâre usually caused by a typo or by an incorrect assumption about how something works. In other words, logic errors happen when thereâs a problem in the logic in your code.
The frustrating thing about computers is that they do exactly what you tell them to, even if what you told them to do didnât make sense, or wasnât what you actually intended. So itâs up to you to make sure your code is telling the computer exactly what you want it to do.
Hereâs an example:
float circleX = width / 2;
float circleY = height / 2;
void setup() {
size(300, 300);
}
void draw() {
background(64);
ellipse(circleX, circleY, 100, 100);
}
Read through this code line by line and try to guess what itâll do when you run it.
You might expect it to draw a circle in the middle of the screen since itâs using width / 2
and height / 2
to find the center. But if you run it, youâll see something like this:
Instead of showing a circle in the middle of the screen, the circle shows up in the upper-left corner. This isnât a syntax error or a runtime error, but thereâs a logic error in the code. Whatâs going on?
In this case, itâs because the code is calculating the circleX
and circleY
variables before the window is created. If youâre using width
and height
, that code needs to be after the call to size()
:
float circleX;
float circleY;
void setup() {
size(300, 300);
circleX = width / 2;
circleY = height / 2;
}
void draw() {
background(64);
ellipse(circleX, circleY, 100, 100);
}
Researching Errors
So far youâve seen a couple example errors, but there are many different kinds of syntax and runtime errors. What should you do when you encounter an error youâve never seen before, or an error you donât understand?
The first thing you should do is take a step back and ask yourself what you expected to happen, and what happened instead. Try to be as specific as possible. What error message are you getting? What line did the error happen on? What did you expect your code to do? What exactly did it do instead?
Read the error message and try to understand what itâs telling you. Error messages can be a little cryptic at first, but they often tell you exactly whatâs going wrong.
Search for the error message or for the unexpected behavior. Paste the error message into google. Try to find posts on Stack Overflow, the Processing forums, or other websites that mention your error, and read through those to get a better understanding of whatâs going on.
Sometimes it can help to search for only parts of the error message. For example, if the error message mentions a variable name that you created, try leaving that variable name out of your search and only including the rest of the error message. You can also wrap the error message in " "
quotation marks to look for an exact match. You can also add âProcessingâ or Javaâ to your search for more specific results.
Doing this type of research is, again, totally normal! Writing code is one part of the process, but debugging, researching, and reading through documentation are just as important.
Print Statements
Another tool that can help you understand why your code is behaving differently from what you expected is the println()
function.
The println
function prints whatever you pass into it to the console. Try running this code and then looking in the console:
void setup() {
size(300, 300);
}
void draw() {
background(64);
println(frameCount);
}
This code prints the value of the frameCount
variable to the console. The frameCount
variable holds how many frames have elapsed since the start of the sketch, so you should see an increasing number in the console.
The println
function can also help with debugging. For example, letâs say you were still trying to figure out why this code generates a NullPointerException
:
String message;
void setup() {
size(300, 100);
textSize(36);
}
void draw() {
background(64);
text(message, 20, 50);
}
If you werenât sure what was going on, you could add a call to println()
to check your assumptions.
String message;
void setup() {
size(300, 100);
textSize(36);
}
void draw() {
background(64);
println("message: " + message);
text(message, 20, 50);
}
Now when you run the code, the value of the message
variable is printed to the console, which can help you understand exactly what the code is doing.
You can use println()
statements to figure out the values of variables, which functions are being called in what order, how many times a loop is iterating, etc.
Debugging with the Debugger
You can also use the debugger that comes with the Processing editor. The debugger is a tool that lets you watch your code run one line at a time.
To activate the debugger, press the debug button- the butterfly-looking circle in the upper-right corner of the Processing editor. That brings up a new Variables
window, which is blank for now.
Now that the debugger is activated, you can use it by following these steps:
- First, set a break point by clicking a line number. The line number should turn into a diamond symbol.
- Now press the play button to run your code using the debugger.
- The debugger will pause the execution of your code when it reaches your break point.
- Then you can use the step button to walk through the code one line at a time.
- The
Variables
window will show the value of every variable as you step through your code.
The whole process looks like this:
The debugger lets you run your code in âslow motionâ and watch the values of variables change as the code runs. Again, the goal of debugging is to figure out exactly where the code does something different from what you expected.
Work in Small Pieces
One final tip Iâll leave you with is to start small and test often. If you try to write your whole program at once and then only run it when youâre done, youâre guaranteed to get a ton of errors.
Instead, test your code by running it and checking that itâs doing what you expected as often as you can. Itâs not unreasonable to re-run your code after every line you write. Donât wait until you think your code is done! Test that each line is doing what you expected. Use print statements to check the value of variables.
Itâs much easier to debug an error when you know itâs on the line of code you just wrote. Itâs a lot harder if you wait until you have dozens of lines of code to debug!
Another tactic you can use when you encounter an error or an unexpected behavior is to isolate the code thatâs confusing you. Start with a new sketch and only add code thatâs directly related to the problem. Code that focuses on the problem is much easier to debug than an entire program that includes a bunch of unrelated code. On the internet, you might hear these isolated programs called an MCVE or an SSCCE.
For example, if your code loads 100 images, gives them random positions and speeds, and has them all bouncing off each other, but you canât get the bouncing to work right, then you should start with a simpler sketch:
- Instead of images, use rectangles.
- Instead of showing 100 of them, only show 2 of them.
- Instead of giving them random positions and speeds, use hard-coded values.
This small example program should still show the same problem as your main sketch. But now itâs much easier to debug, because you donât have to look at any of the code that has nothing to do with the problem.
Half the time youâll figure out your problem while trying to narrow your problem down to a smaller example sketch.
Other Debugging Tips
All of the above approaches will help you debug your code, but âd be remiss if I didnât mention a couple other debugging tactics!
Rubber Duck Debugging
Another really useful approach for debugging is to try explaining your problem out loud. You donât even have to be talking to another person! A rubber duck will do just fine. đŠ
Rubber duck debugging is the process of explaining your problem to an inanimate object (or a pet, or a houseplant). By restating your problem in your own words, you force your brain to think about it from a different perspective. This often gives you that âah-ha!â moment that helps you figure out your problem. (This is also why youâll often figure out your problem when you start writing a question to post in a forum or on Stack Overflow.)
You can learn more about rubber duck debugging here and here.
Take a Break
If youâre stuck on a particularly confusing piece of code, one of the best things you can do is get away from the computer. Go on a walk, pet your cat, and try to clear your head. Youâll be amazed at how many solutions you end up thinking of in the shower.
Get Help
You arenât alone! If youâre still having trouble with an error or with code thatâs doing something different from what you expected, you can reach out for help!
Try to isolate your problem to a small example program and come say hello on the Happy Coding forum!
Comments and Questions
Happy Coding is a community of folks just like you learning about coding.
Do you have a comment or question? Post it here!