---
title: "Body"
author: "Jürgen Altfeld"
date: "`r Sys.Date()`"
output:
    rmarkdown::html_vignette
# Vignette marker to signal a dependent sub document that shall not be rendered as separate vignette
# This shall replace the current workaround to use Rmd child files for vignettes
# once the gap is closed in R and knitor.
# See:
# https://github.com/yihui/knitr/issues/1540
# https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17416
vignette: >
  %\VignetteEngine{none}
---


# Introduction into conditions in standard R

## What is a condition?

The execution of an R script can be interrupted to signal special states (*conditions*) like:

- errors
- warnings
- info messages
- user requested interrupts (by hitting CTRL + C/BRK or ESC)

For details see the R help:   `?conditions`



## Condition examples

```{r setup, include=FALSE}
# knitr::opts_chunk$set(echo = TRUE, error = TRUE)  # render R errors as output instead of stopping to knit
```

An error condition:
```{r, error = TRUE}
log("text")   # calculating the logarithm of a string throws an error
```


A warning condition:
```{r, results='hold'}
log(-1)                # logarithm of a negative number throws a warning
```



# Throw your own conditions

Note: This text will never be shown due to a "limitation by design" of pandoc:

https://stackoverflow.com/a/31778080/4468078



## Throw an Error

Use `stop` to throw an error "condition" to signal an invalid program state:
```{r, error = TRUE}
if (1 != 2)
  stop("something is wrong")
```

</br>
Or shorter (but without a way to specify an error text):
```{r, error = TRUE}
stopifnot(1 == 2)
```
`stopifnot` is quite often used to ensure pre-conditions in function calls.



## Throw a Warning

```{r}
warning("bad weather today, don't forget your umbrella")
```

## Throw a Message

```{r}
message("good morning")
```



# Handling conditions in R

Scroll down for examples...

## Unhandled errors stop R

By default R will stop the execution if an error occurs:
```{r, error = TRUE, eval = TRUE}
options(error = NULL)  # switch to default behaviour of pure R

test <- function() {
  log("not a number")
  print("R does stop due to an error and never executes this line")
}

test()     # throws an error
```
Note that the output does **not** show the `print` result since the execution stops in case of an error.



## Use `try` to ignore errors

With the `try` function you can handle errors to continue the execution (by ignoring the error):
```{r, error = TRUE, collapse = FALSE, eval = TRUE}
try(log("not a number"), silent = TRUE)
print("errors can't stop me")
```

**Note:** If an error occurs then the error message is printed to the `stderr` connection
unless the call includes `silent = TRUE`.



## Use `tryCatch` to handle errors

With `tryCatch` you can handle errors as you want:
```{r}
an.error.occured <- FALSE
tryCatch( { result <- log("not a number"); print(res) }
          , error = function(e) {an.error.occured <<- TRUE})
print(an.error.occured)
```

</br>
If you use an error handler function

 * the error is not shown anymore and
 * the execution continues after the `tryCatch` statement.



## `tryCatch` can handle all conditions 1/2

... not only errors. Just use the condition name as parameter to handle conditions of this type, e. g. warnings:

```{r}
tryCatch( { result <- log(-1); print(result) }
          , warning = function(w) { print("Hey, a warning") })
```


## `tryCatch` can handle all conditions 2/2

You can use `error`, `warning`, `message` or `interrupt` as parameter name to assign a handler for these "standard" conditions, e. g. to catch messages:

```{r}
last.message <- NULL
tryCatch( { message("please handle me"); print("Done") }
          , message = function(m) { last.message <<- m })
print(last.message$message)
```



## Advanced topic: User defined conditions

You can even define your own user-defined condition classes, but
there is no built-in function to generate a new object of class `condition`.
So do it yourself:*

```{r}
condition <- function(subclass, message, call = sys.call(-1), ...) {
  structure( class = c(subclass, "condition"),
             list(message = message, call = call, ...))
}

tryCatch( { work <- condition("my.work.condition", "after work party")
            signalCondition(work); print("Done") }
          , my.work.condition = function(c) { print(c$message) })
```

User-defined condition classes are only required if you want to implement a specific recovery strategy for
this condition. This is out of scope of this presentation.

*) Source: <http://adv-r.had.co.nz/beyond-exception-handling.html>



## But `tryCatch` is not perfect

Have you discovered the problem in the previous examples?

See the next chapter for the answer!




# The drawbacks of `tryCatch`

## Handling a condition stops the execution 1/2

Calling the function **without** a `tryCatch` handler does **not stop** the
execution of the function `f()`:

```{r}
{ # required to execute the code as one block to summarize the output in this Rmd
  f <- function() {
    warning("deprecated function called")
    print("Hello world")
  }
  f()
  print("Done")
}
```

but...



## Handling a condition stops the execution 2/2

Handling a condition **cancels** the execution of the code block that raised (throwed) the condition:

```{r, echo=FALSE}
# dummy code to avoid a "missing function" error in the next code junk
write.to.log <- function(msg) { invisible() }
```


```{r}
f <- function() {
  warning("deprecated function called")
  print("Hello world")
}
tryCatch(f(), warning = function(w) { write.to.log(w) })
print("Done")
```

**Observe:** *Hello world* is never printed just because we catched a warning!

**If you catch a condition with `tryCatch` (even just a warning or message) then R**

1. executes the condition handler function
1. aborts the execution of the code block that throwed the condition
1. continues the execution with **the next command after the `tryCatch` command**




## Handling errors unrolls the stack trace 1/2

If you do **not catch an error** R stops and you can get the complete function call stack using `traceback`
to identify the code that throwed the error:

```{r, error = TRUE, eval = FALSE}
options(error=function() traceback(2)) # http://stackoverflow.com/a/13119318/4468078
f <- function() {
  log("not a number")
  print("Hello world")
}
f()
```

```{r, eval = FALSE}
Error in log("not a number") :
  non-numeric argument to mathematical function
6: (function ()
   traceback(2))() at f.R#3
5: f() at f.R#6
...
1: source("f.R")
```

**Note:** The call stack shows the line number after the file name and hash sign, e. g. `file1.R#7` = line number 7



## Handling errors unrolls the stack trace 2/2

But if you handle the error, the call stack is truncated:

```{r, error = TRUE, eval = FALSE}
f <- function() {
  log("not a number")
  print("Hello world")
}
tryCatch(f(), error = function(e) { traceback() })
```

```{r, eval = FALSE}
8: value[[3L]](cond)
7: tryCatchOne(expr, names, parentenv, handlers[[1L]])
6: tryCatchList(expr, classes, parentenv, handlers)
5: tryCatch(f(), error = function(e) {
       traceback(2)
   }) at f.R#5
...
1: source("f.R")
```

The call stack ends basically with the `tryCatch` call but **does not show you the code line in `f()`
where the error was thrown**.


## Summary: The drawbacks of `tryCatch`

1. **You can not find out the exact reason for errors** because the full stack trace is truncated

2. Handling of warnings and messages (e. g. just to log them) cancels
   the execution of the code block that throwed the condition (what is unexpected!)

See the next chapters for possible work-arounds...




# Workaround 1: Interactive debugging

## Interactive debugging

You can run and debug your R script interactively in the *RGui* or [RStudio](https://www.rstudio.com/products/rstudio/)
instead of condition handling with `tryCatch`.

For more details on interactive debugging see `?debug`.

**Note: Interactive debugging is out of scope of this presentation.**



## Limitations of interactive debugging

Interactive debugging is very difficult in case of

- errors that are not (easily) reproducible.
- errors that occur only after a long run time
- batch jobs running on a server (you have no interactive GUI then!)



# Workaround 2: `withCallingHandlers` + `tryCatch`


## How `withCallingHandlers` works

`withCallingHandlers` works similar to `tryCatch` but

1. remembers the call stack down to the point where the condition was signaled
2. resumes the execution after the point where the condition was signaled

```{r}
f <- function() {
  warning("deprecated function called")
  print("Hello world")
}
withCallingHandlers(f(), warning = function(w) { write.to.log(sys.calls()) })
```

**Note:** Use **`sys.calls`** within `withCallingHandlers` to return the full **call stack**.



## `withCallingHandlers` supports restarts

*Restarts* allow to recover from conditions using a predefined behaviour:

```{r, results = 'hold'}
f <- function() {
  warning("deprecated function called")
  print("Hello old world")
}
withCallingHandlers(f(), warning = function(w) { write.to.log(sys.calls())
                                                 invokeRestart("muffleWarning")})
print("Done")
```

`invokeRestart("muffleWarning")` has a simple recovery strategy: "Suppress the warning".

It consumes the warning (so it does not "bubble up" to higher function call levels)
and resumes the execution.

*TODO: Mention other restarts and their behaviour...*



## Differences between `withCallingHandlers` and `tryCatch`

|                       | tryCatch               | withCallingHandlers         |
|-----------------------|----------------------- |-----------------------------|
| **Program execution** | **breaks** and continues with the first expression after the `tryCatch` function call | **resumes** the execution at the code line that throwed the condition |
| **Call stack** (`traceback` and `sys.calls`) | **unwinds the call stack** up to the `tryCatch` function call |  **keeps the full call stack** down to the code line that throwed the condition |
| **Rethrowing of conditions** | **Conditions are consumed** by the called handler function (do not bubble up) | **Conditions bubble up** (are not consumed by the called handler function) |

**Note: `tryCatch` is different from Java's `try-catch` statement: It unwinds the call stack (in Java you get the
full call stack with the `printStackTrace` method)!**



## Combine `withCallingHandlers` with `tryCatch`

The requirements for better condition handling in R are:

- Get the full call stack for all catched conditions
- Resume execution after handling warnings and messages
- Catch errors and continue the execution after the handler function

Solution:

- Handle all conditions in `withCallingHandlers` to log them with the full stack trace
- Invoke a restart in `withCallingHandlers` to resume after a non-error condition
- Handle only errors in `tryCatch` to recover from the error and continue execution after the `tryCatch` function call



## Code snippet for better error handling

An improved "error handler" in R looks similar to this code snippet:
```{r, results='hold'}
f <- function() {
  warning("deprecated function called")
  print("A warning cannot stop me")
  log("not a number")
  print("Hello old world")
}

tryCatch(withCallingHandlers(f(), error=function(e) {write.to.log(sys.calls())}
                                , warning=function(w) {write.to.log(sys.calls())
                                                invokeRestart("muffleWarning")})
         , error = function(e) { print("recovered from error") })
print("Done")
```

**This is basically how the `tryCatchLog` package works internally!**



## How about usability?

**Do you really want to use that much boilerplate code in your R scripts at every place
where you have to catch errors and conditions?**

If not: See the the next chapter to learn how the package `tryCatchLog` could make your life much easier!

