---
title: "Mean Relative Indifference"
subtitle: "A Comparison of R Comparison Functions"
author: "Brodie Gaslam"
output:
    rmarkdown::html_vignette:
        toc: true
        css:
          - !expr diffobj::diffobj_css()
          - styles.css
vignette: >
  %\VignetteIndexEntry{Comparison Functions}
  %\VignetteEngine{knitr::rmarkdown}
  \usepackage[utf8]{inputenc}

---

```{r, echo=FALSE}
library(diffobj)
old.opt <- options(
  diffobj.disp.width=80, diffobj.pager="off", diffobj.format="html"
)
```

Most R object comparison functions are good at telling you that
objects are different, but less so at conveying _how_ they are
different.  I wrote `diffobj` to provide an "aha, that's how they are different"
comparison.  In this vignette I will compare `diffPrint` to `all.equal` and to
`testthat::compare`.

> Update: `testthat` now uses `waldo`, which internally uses `diffobj` to
> compute diffs.  `waldo::compare` does a much better job of reporting
> differences than the old `testthat::compare`.

Disclaimer: I picked the examples here to showcase `diffobj` capabilities, not
to carry out a fair and balanced comparison of these comparison functions.
Nonetheless, I hope you will find the examples representative of common
situations where comparison of R objects is useful.

## Vectors

I defined four pairs of numeric vectors for us to compare.  I purposefully hid
the variable definitions to simulate a comparison of unknown objects.

```{r echo=FALSE}
A1 <- 1:10
B1 <- c(1:9, 11)
A2 <- 1:20
B2 <- c(20, 1:19)
A3 <- 1:20
B3 <- c(20:21, 1:19)
```

### Stage 1

```{r}
all.equal(A1, B1)
```

The objects are different...  At this point I would normally print both `A1` and
`B1` to try to figure out how that difference came about since the "mean
relative difference" is unhelpful.

```{r}
testthat::compare(A1, B1)
```

`testthat::compare` does a better job, but I still feel the need to look at `A1`
and `B1`.

```{r, results="asis"}
diffPrint(A1, B1)
```

Aha, that's how they are different!

### Stage 2

Let's up the difficulty a little bit:

```{r}
testthat::compare(A2, B2)
```

If you look closely you will see that despite a reported 20/20 differences, the
two vectors are actually similar, at least in the part visible part of the
output. With `diffPrint` it is obvious that `B2` and is the same as `A2`, except
that the last value has been moved to the first position:

```{r, results="asis"}
diffPrint(A2, B2)
```

### Stage 3

`testthat::compare` throws in the towel as soon as lengths are unequal:

```{r}
testthat::compare(A3, B3)
```

`all.equal` does the same.  `diffPrint` is unfazed:

```{r, results="asis"}
diffPrint(A3, B3)
```

`diffPrint` also produces useful output for largish vectors:

```{r, results="asis"}
A4 <- 1:1e4
B4 <- c(1e4 + 1, A4[-c(4:7, 9e3)])
diffPrint(A4, B4)
```

Do note that the comparison algorithm scales with the square of the number of
_differences_, so very large and different vectors will be slow to process.

## Objects

R Core and package authors put substantial effort into `print` and `show`
methods.  `diffPrint` takes advantage of this.  Compare:

```{r, R.options=list(max.print=5)}
all.equal(iris, iris[-60,])
```

to:

```{r, results="asis"}
diffPrint(iris, iris[-60,])
```

And:

```{r, R.options=list(max.print=5)}
all.equal(lm(hp ~ disp, mtcars), lm(hp ~ cyl, mtcars))
```

to:

```{r, results="asis"}
diffPrint(lm(hp ~ disp, mtcars), lm(hp ~ cyl, mtcars))
```

In these examples I limited `all.equal` output to five lines for the sake of
brevity.  Also, since `testthat::compare` reverts to `all.equal` output with
more complex objects I omit it from this comparison.

## Parting Thoughts

Another candidate comparison function is `compare::compare`.  I omitted it from
this vignette because it focuses more on similarities than on differences.
Additionally, `testthat::compare` and `compare::compare` `print` methods
conflict so they cannot be used together.

For a more thorough exploration of `diffobj` methods and their features please see the [primary `diffobj` vignette](diffobj.html).

```{r, echo=FALSE}
options(old.opt)
```

