It does work and it’s R’s fault!

We’ve all been there: you’re sure your code is perfect and yet the machine isn’t doing what it “should.” Of course, this always means the problem is that your code is broken – you’ve made a false assumption, you’ve skipped a step that you thought you included, etc. – but in general, people don’t like to be wrong, and chances are good that you’re a person.

So how can you shift your thinking to get moving again when you’re stuck and frustrated?

Play, play and play some more!

When we communicate with other people, most of us try to avoid making statements that have obvious errors or that are going to elicite a negative response. For many folks, when you first start programming it’s natural to instictively avoid entering expressions that seem to have a high likelihood of failure.

But, of course, the R interpreter isn’t actually going to judge you! In fact, it’s (close to) impossible for you to do anything that’s going to break* R or the server. If you find an edge case that I haven’t protected you from yet, it only takes about 30s for us to reboot.

So this is all to say that you SHOULD try to run expressions that will fail! If a function isn’t doing what you expect it do in your code then PLAY with it! Throw crazy data at it and see what happens! Errors are awesome; you learn more from them than code that silently does wierd stuff.

  • Footnote: about the most descructive thing you can do is erase all of your files. Please don’t do that.

Try to invalidate your assumptions

Instictively, most people will lean towards asking questions that validate, instead of invalidate, their assumptions. In science, we have to opperate differently: in most fields you spend most of your time running negative controls. Think about coding the same way.

Two quick-and-dirty tools that can be useful in testing your assumptions are print and class.

Print is a lightweight way to insert checks into your code when you’re debugging. Here’s a contrived example:

f <- function(a, b) {
  
  c <- a - 1
  
  b / c
}

f(2, 1)
## [1] 1
# This returns something crazy!
f(1, 2)
## [1] Inf

It’s easy to see what’s happening here, but if this function were more complex it might not be. Let’s use print to insert a sanity check into our code.

Print will print out a representation of the object you pass it, just as if you’d evaluated that object in the console:

f <- function(a, b) {
  
  c <- a - 1
  
  print(c)
  
  b / c
}

f(2, 1)
## [1] 1
## [1] 1
# This returns something crazy!
f(1, 2)
## [1] 0
## [1] Inf

So we’ve made our denominator; hence our wierd division result.

Class will tell you what type of object a value holds. Here’s a common rough edge I’ve been seeing folks get stuck on:

f <- function(a, b) {
  
  c <- a - 1
  d <- b / c
  
}

f(2, 1)

Why no number R??? Well, how about we capture our function’s return in a variable:

e <- f(2, 1)
class(e)
## [1] "numeric"

What is it? Can we make sense of that?

print(e)
## [1] 1

Here’s the function you probably meant to implement:

f <- function(a, b) {
  
  c <- a - 1
  b / c
  
}