<!--
%\VignetteEngine{knitr::rmarkdown}
%\VignetteIndexEntry{Introduction to dots}
-->

Introduction to `dots`
==================

If you wish, you can view this vignette online [here](http://lcolladotor.github.io/dots/).


```{r vignetteSetup, echo=FALSE, message=FALSE, warning = FALSE}
## Track time spent on making the vignette
startTime <- Sys.time()

## Bib setup
library('knitcitations')

## Load knitcitations with a clean bibliography
cleanbib()
cite_options(hyperlink = 'to.doc', citation_format = 'text', style = 'html')
# Note links won't show for now due to the following issue
# https://github.com/cboettig/knitcitations/issues/63

## Write bibliography information
write.bibtex(c(knitcitations = citation('knitcitations'),
    dots = citation('dots'), 
    knitrBootstrap = citation('knitrBootstrap'), 
    knitr = citation('knitr')[3],
    rmarkdown = citation('rmarkdown')),
    file = 'dotsRef.bib')
bib <- read.bibtex('dotsRef.bib')

## Assign short names
names(bib) <- c('knitcitations', 'dots', 'knitrBootstrap',
    'knitr', 'rmarkdown')
```


# Overview


`dots` `r citep(bib[['dots']])` is a simple package that helps you simplify your function definitions by using the `...` arguments. This reduces the complexity a new user of your package will face when reading its documentation. At the same time, `dots` allows you to define advanced arguments which you can then define inside your functions. Experienced users will be able to use them thus controlling those fine parameters most users do not need.


## dots()

The main function in this package is `dots()`.  It will look inside `...` to see if `name` has been used. If it has, it will return its value. Otherwise, it returns a default `value`.

```{r 'library'}
## Load the library
library('dots')
```


```{r 'dotsCode', bootstrap.show.output = FALSE}
## Explore code
## Alias: advanced...()
dots
```

The idea of this fairly simple function is to use it inside your functions to define advanced arguments and give them default values.


The following example defines `myFun()` which needs the argument `x` to work. Inside `myFun()`, `dots()` is used to define the advanced argument `verbose` which the developer of `myFun()` thinks users will rarely want to use. This developer still wants to give users the flexibility to control this argument but doesn't want to confuse the majority of its users with a huge argument list. 

```{r 'dotsExample'}
myFun <- function(x, ...) {
    ## In all the cases, the user has to specify 'x' for this function to work
    
    ## However, only a few users will want to make the function print status
    ## reports (controlled by the 'verbose' argument)
    
    #' @param verbose Controls whether to print status reports or not.
    #' Use value from global 'verbose' option if available. Otherwise, use 
    #' \code{FALSE}
    verbose <- dots('verbose', getOption('verbose', FALSE), ...)
    if(verbose)
        message(paste(Sys.time(), 'myFun: performing analysis'))
    
    ## In this case, it's just a simple example, so lets return the identify value
    return(identity(x))
}

## Lets use it now
myFun(1:10)

## Experienced user wants to print status reports
myFun(1:10, verbose = TRUE)
```

Ok, this is an example and there are really only two arguments but in practice things can get complicated fast. As a developer, soon you might find yourself with functions that have 10 or more arguments and need to cut the list down to promote friendliness and usability of your code.


Note that if you are using the same advanced argument inside several functions, you might want to consider using the function `getOption()`. It's useful for users who want to set global options and don't want to specify them for every single function call.

We highly recommend documenting any advanced arguments using [roxygen2](http://cran.r-project.org/web/packages/roxygen2/index.html) tags inside the source code so experienced users can understand the code. We also recommend explaining these advanced arguments in your package vignette at the section targeting advanced users.

That is, we expect experienced users to be able to dig into either the source code and/or find the appropriate docs section. As a package developer you have to give them a place to find such documentation.

## formal_call()

Once you start using the `...` argument, you will soon find use cases where you are using  `...` for several functions, but then some of them might complain when `...` contains an argument they don't use. In such scenarios you will want to run the function using some key arguments, remaining arguments from `...` that the function was defined to use, and drop the unwanted arguments in `...`.

That's where `formal_call()` comes into play.

```{r 'formalCallCode', bootstrap.show.output = FALSE}
## Explore source
## Alias: formalCall()
formal_call
```

### Basic example

The following example shows how you can use `formal_call()` inside your functions. First, lets try a simple function that will return the identity of the maximum value of a vector `x`.

```{r 'formalCodeExample'}
myFunBroken <- function(x, ...) {
    identity(max(x, ...), ...)
}

## Test without using ...
myFunBroken(1:10)
```

That worked because we are not using the `...` argument. However, as is the code will break when using `...` because `identity()` does not have have other arguments defined.

```{r 'formalBroken', eval = FALSE}
## Breaks when you use ...
myFunBroken(1:10, 11:20)
```

We can fix the broken code by using `formal_call()` as shown below.

```{r 'formalFixed'}
## Fix code using formal_call()
myFunFixed <- function(x, ...) {
    formal_call(identity, x = max(x, ...), ...)
}

## Check that we are getting the same value as before
identical(myFunBroken(1:10), myFunFixed(1:10))

## Doesn't break when you use ...
myFunFixed(1:10, 11:20)
```

In this particular example, you could dodge the problem by using `identity(x)` instead of `identity(x, ...)`. However, the illustrative use of `formal_call()` remains and there are more complicated cases where you will need to use it.

### Complex example

In the following example we want a function that does things with `...` (in this case, it defines the `verbose` argument) and then pass it to `plot()`. Simply using `dots()` is not enough as `plot()` will complain that `verbose` is not a graphical parameter.

```{r 'funkyPlot'}
## A more complicated example
funkyPlot <- function(x, y, ...) {
    verbose <- dots('verbose', getOption('verbose', FALSE), ...)
    if(verbose)
        message(paste(Sys.time(), 'funkyPlot: getting ready to roll'))
    plot(x, y, ...)
}

## funkyPlot() doesn't work
tryCatch(funkyPlot(1:10, 10:1, verbose = TRUE, xlab = 'Data (units)'), warning = function(w) { print(w) })
```

There are many graphical parameters, but they are not part of the formal definition of `plot()`. We can solve this by using the advanced argument `formalCallUse` which specifies arguments we still want to use even if they are not part of the formal definition.

Below we do so only for the `xlab` graphical parameter.


```{r 'funkyPlot2'}
## Use 'xlab'
funkyPlot2 <- function(x, y, ...) {
    verbose <- dots('verbose', getOption('verbose', FALSE), ...)
    if(verbose)
        message(paste(Sys.time(), 'funkyPlot: getting ready to roll'))
    xlab <- dots('xlab', '', ...)
    formal_call(plot, x = x, y = y, ..., formalCallUse = list(xlab = xlab))
}

## Works now =)
funkyPlot2(1:10, 10:1, verbose = TRUE, xlab = 'Data (units)')
```

If you have a small number of advanced arguments you want users to be able to use, this approach will work. But in the case of `plot()` there are tons of graphical parameters that we want users to be able to use. 

If you knew for certain that the other functions inside yours only use a small number of arguments passed through `...` (`verbose` in our example), you can eliminate them from `...` yourself and pass them to `formalCallUse`.

```{r 'funkyPlot3'}
## If we knew for sure that we only want to exclude 'verbose' from ... before
## calling plot() we can do so this way.
funkyPlot3 <- function(x, y, ...) {
    verbose <- dots('verbose', getOption('verbose', FALSE), ...)
    if(verbose)
        message(paste(Sys.time(), 'funkyPlot: getting ready to roll'))
    
    ## Drop 'verbose' from ...
    use <- list(...)
    use <- use[!names(use) == 'verbose']
    
    ## Call plot. Note that we are not passing ... anymore.
    formal_call(plot, x = x, y = y, formalCallUse = use)
}

## Works with more graphical parameters
funkyPlot3(1:10, 10:1, verbose = TRUE, xlab = 'Data (units)', ylab = 'Success', main = 'Complicated example')
```

So for these very complicated use cases, `formalCallUse` can help you when you either want to make sure you are supplying a small set of arguments or if you have a small set you want to exclude.

Cases where there are many arguments to either exclude or supply are nasty either way.

# Learn more

If you want to check other examples using `dots()`, check the functions `last()` and `recursive_last()`.

You can also see how these functions are used in packages such as `derfinder`: [Biconductor page](http://www.bioconductor.org/packages/release/bioc/html/derfinder.html), [GitHub code](https://github.com/lcolladotor/derfinder).



# Reproducibility

Code for creating the vignette

```{r createVignette, eval=FALSE, bootstrap.show.code=FALSE}
## Create the vignette
library('knitrBootstrap') 

knitrBootstrapFlag <- packageVersion('knitrBootstrap') < '1.0.0'
if(knitrBootstrapFlag) {
    ## CRAN version
    library('knitrBootstrap')
    system.time(knit_bootstrap('dots.Rmd', chooser=c('boot', 'code'), show_code = TRUE))
    unlink('dots.md')
} else {
    ## GitHub version
    library('rmarkdown')
    system.time(render('dots.Rmd'))
}
unlink('dotsRef.bib')
## Note: if you prefer the knitr version use:
# library('rmarkdown')
# system.time(render('dots.Rmd', 'html_document'))

## Extract the R code
library('knitr')
knit('dots.Rmd', tangle = TRUE)
```

Date the vignette was generated.

```{r reproducibility1, echo=FALSE, bootstrap.show.code=FALSE}
## Date the vignette was generated
Sys.time()
```

Wallclock time spent generating the vignette.

```{r reproducibility2, echo=FALSE, bootstrap.show.code=FALSE}
## Processing time in seconds
totalTime <- diff(c(startTime, Sys.time()))
round(totalTime, digits=3)
```

`R` session information.

```{r reproducibility3, echo=FALSE, bootstrap.show.code=FALSE, bootstrap.show.message=FALSE}
## Session info
library('devtools')
options(width = 90)
session_info()
```

# Bibliography

This vignette was generated using `knitrBootstrap` `r citep(bib[['knitrBootstrap']])`
with `knitr` `r citep(bib[['knitr']])` and `rmarkdown` `r citep(bib[['rmarkdown']])` running behind the scenes.

Citations made with `knitcitations` `r citep(bib[['knitcitations']])`.

```{r vignetteBiblio, results='asis', echo=FALSE}
## Print bibliography
bibliography()
```
