class: center, middle, inverse, title-slide .title[ # Debugging and defensive programming ] .author[ ### INFO 5940
Cornell University ] --- ## Bugs <img src="../../../../../../../../img/grace-hopper.jpg" width="80%" style="display: block; margin: auto;" /> --- ## Bugs > An error, flaw, failure or fault in a computer program or system that causes it to produce an incorrect or unexpected result, or to behave in unintended ways. * Computers are powerful tools that are incredibly stupid * Debugging has two goals: 1. Prevent bugs from occurring in the first place 1. Fix bugs once they occur --- class: inverse, middle # Defensive programming --- ## Defensive programming * Style guide * Failing fast --- ## Writing code Programming | Language ------------|---------- Scripts | Essays Sections | Paragraphs Lines Breaks | Sentences Parentheses | Punctuation Functions | Verbs Variables | Nouns --- weve grown used to wonders in this century its hard to dazzle us but for 25 years the united states space program has been doing just that weve grown used to the idea of space and perhaps we forget that weve only just begun were still pioneers they the members of the Challenger crew were pioneers and i want to say something to the school children of America who were watching the live coverage of the shuttles takeoff i know it is hard to understand but sometimes painful things like this happen its all part of the process of exploration and discovery its all part of taking a chance and expanding mans horizons the future doesnt belong to the fainthearted it belongs to the brave the challenger crew was pulling us into the future and well continue to follow them the crew of the space shuttle challenger honored us by the manner in which they lived their lives we will never forget them nor the last time we saw them this morning as they prepared for the journey and waved goodbye and slipped the surly bonds of earth to touch the face of god --- We've grown used to wonders in this century. It's hard to dazzle us. But for 25 years the United States space program has been doing just that. We've grown used to the idea of space, and perhaps we forget that we've only just begun. We're still pioneers. They, the members of the Challenger crew, were pioneers. And I want to say something to the school children of America who were watching the live coverage of the shuttle's takeoff. I know it is hard to understand, but sometimes painful things like this happen. It's all part of the process of exploration and discovery. It's all part of taking a chance and expanding man's horizons. The future doesn't belong to the fainthearted; it belongs to the brave. The Challenger crew was pulling us into the future, and we'll continue to follow them.... The crew of the space shuttle Challenger honoured us by the manner in which they lived their lives. We will never forget them, nor the last time we saw them, this morning, as they prepared for the journey and waved goodbye and 'slipped the surly bonds of earth' to 'touch the face of God.' -- * [Reagan's address](https://youtu.be/Qa7icmqgsow) --- ## Object names ```r # Good day_one day_1 # Bad first_day_of_the_month DayOne dayone djm1 ``` --- ## Overwriting objects ```r # Bad T <- FALSE c <- 10 ``` ```r x <- seq(from = 1, to = 10) mean(x) ``` ``` ## [1] 5.5 ``` ```r # create new mean function mean <- function(x) sum(x) mean(x) ``` ``` [1] 55 ``` --- ## Line length ```r # Good scdbv <- scdbv %>% mutate(chief = factor(chief, levels = c("Jay", "Rutledge", "Ellsworth", "Marshall", "Taney", "Chase", "Waite", "Fuller", "White", "Taft", "Hughes", "Stone", "Vinson", "Warren", "Burger", "Rehnquist", "Roberts"))) # Bad scdbv <- mutate(scdbv, chief = factor(chief, levels = c("Jay", "Rutledge", "Ellsworth", "Marshall", "Taney", "Chase", "Waite", "Fuller", "White", "Taft", "Hughes", "Stone", "Vinson", "Warren", "Burger", "Rehnquist", "Roberts"))) ``` --- ## Indentation ```r # pure function long_function_name <- function(a = "a long argument", b = "another argument", c = "another long argument") { # As usual code is indented by two spaces. } # in a mutate() function scdbv <- scdbv %>% mutate(majority = majority - 1, chief = factor(chief, levels = c("Jay", "Rutledge", "Ellsworth", "Marshall", "Taney", "Chase", "Waite", "Fuller", "White", "Taft", "Hughes", "Stone", "Vinson", "Warren", "Burger", "Rehnquist", "Roberts"))) ``` --- ## Calling functions ```r library(purrr) map() ``` -- ```r library(purrr) library(maps) map() ``` --- ## `::` notation ```r library(purrr) library(maps) purrr::map() # use map() from the purrr library maps::map() # use map() from the maps library ``` -- ```r library(purrr) map() # use map() from the purrr library maps::map() # use map() from the maps library ``` --- ## Auto-formatting in RStudio * **Code > Reformat Code** (Shift + Cmd/Ctrl + A) * **Code > Reindent Lines** (Cmd/Ctrl + I) * [`styler`](http://styler.r-lib.org/) --- ## Demonstration: styling code with `styler` * [This code example](/notes/style-guide/#exercise-style-this-code) --- class: inverse, middle # Condition handling --- ## Fatal errors ```r addition <- function(x, y){ if(!is_numeric(c(x, y))) stop("One of your inputs is not a number.") x + y } addition(3, "abc") ``` ``` ## Error in addition(3, "abc"): One of your inputs is not a number. ``` --- ## Warnings ```r logit <- function(x){ log(x / (1 - x)) } logit(-1) ``` ``` ## Warning in log(x/(1 - x)): NaNs produced ``` ``` ## [1] NaN ``` --- ## Warnings ```r logit <- function(x){ if (x < 0 | x > 1) stop('x not between 0 and 1') log(x / (1 - x)) } logit(-1) ``` ``` ## Error in logit(-1): x not between 0 and 1 ``` --- ## Warnings ```r logit <- function(x){ x <- if_else(x < 0 | x > 1, NA_real_, x) if (is.na(x)) warning('x not between 0 and 1') log(x / (1 - x)) } logit(-1) ``` ``` ## Warning in logit(-1): x not between 0 and 1 ``` ``` ## [1] NA ``` --- ## Messages ```r ggplot(diamonds, aes(carat, price)) + geom_point() + geom_smooth() ``` ``` ## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")' ``` <img src="index_files/figure-html/message_ggplot-1.png" width="55%" style="display: block; margin: auto;" /> --- ## Suppressing messages ```r demo_message <- function() message("This is a message") demo_message() ``` ``` ## This is a message ``` ```r suppressMessages(demo_message()) # no output demo_print <- function() print("This is a message") demo_print() ``` ``` ## [1] "This is a message" ``` ```r suppressMessages(demo_print()) # still output ``` ``` ## [1] "This is a message" ``` --- ## Exercise: build a function with conditions <img src="https://media.giphy.com/media/5EJHDSPpFhbG0/giphy.gif" width="80%" style="display: block; margin: auto;" />
10
:
00
--- <img src="../../../../../../../../img/debugging.jpg" alt="A cartoon of a fuzzy round monster face showing 10 different emotionsexperienced during the process of debugging code. The progression goes from (1) 'Igot this' - looking determined and optimistic; (2) 'Huh. Really thought that was it.'- looking a bit baffled; (3) '...' - looking up at the ceiling in thought; (4) 'Fine.Restarting.' - looking a bit annoyed; (5) 'OH WTF.' Looking very frazzled andfrustrated; (6) 'Zombie meltdown.' - looking like a full meltdown; (7) (blank) -sleeping; (8) 'A NEW HOPE!' - a happy looking monster with a lightbulb above; (9)'insert awesome theme song' - looking determined and typing away; (10) 'I lovecoding' - arms raised in victory with a big smile, with confetti falling." width="80%" style="display: block; margin: auto;" /> .footnote[Source: [Allison Horst](https://github.com/allisonhorst/stats-illustrations)] --- ## Debugging techniques 1. Realize that you have a bug 1. Make it repeatable 1. Figure out where it is 1. Fix it and test it --- ## The call stack ```r f <- function(a) g(a) g <- function(b) h(b) h <- function(c) i(c) i <- function(d) "a" + d f(10) ``` ``` ## Error in "a" + d: non-numeric argument to binary operator ``` ```r traceback() ``` ``` # 4: i(c) at exceptions-example.R#3 # 3: h(b) at exceptions-example.R#2 # 2: g(a) at exceptions-example.R#1 # 1: f(10) ``` --- ## Condition handling * Unexpected errors * Expected errors * `safely()` --- ## Dealing with failure using `safely()` * Adverb * Always returns a list with two elements 1. `result` 1. `error` --- ## Dealing with failure using `safely()` ```r safe_sqrt <- safely(sqrt) str(safe_sqrt(9)) ``` ``` ## List of 2 ## $ result: num 3 ## $ error : NULL ``` ```r str(safe_sqrt("a")) ``` ``` ## List of 2 ## $ result: NULL ## $ error :List of 2 ## ..$ message: chr "non-numeric argument to mathematical function" ## ..$ call : language .Primitive("sqrt")(x) ## ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition" ``` --- ## `safely()` and `map()` ```r x <- list("a", 4, 5) # unsafely square root y <- map(x, sqrt) ## Error in .Primitive("sqrt")(x): non-numeric argument to mathematical function # safely log y <- map(x, safely(sqrt)) str(y) ## List of 3 ## $ :List of 2 ## ..$ result: NULL ## ..$ error :List of 2 ## .. ..$ message: chr "non-numeric argument to mathematical function" ## .. ..$ call : language .Primitive("sqrt")(x) ## .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition" ## $ :List of 2 ## ..$ result: num 2 ## ..$ error : NULL ## $ :List of 2 ## ..$ result: num 2.24 ## ..$ error : NULL ``` --- ## `transpose()` ```r y <- transpose(y) str(y) ``` ``` ## List of 2 ## $ result:List of 3 ## ..$ : NULL ## ..$ : num 2 ## ..$ : num 2.24 ## $ error :List of 3 ## ..$ :List of 2 ## .. ..$ message: chr "non-numeric argument to mathematical function" ## .. ..$ call : language .Primitive("sqrt")(x) ## .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition" ## ..$ : NULL ## ..$ : NULL ``` --- ## Exercise: handle conditions using `safely()` <img src="https://media.giphy.com/media/VFDeGtRSHswfe/giphy.gif" width="80%" style="display: block; margin: auto;" />
05
:
00