---
title: "Return Values and Side Effects"
author: "Statistical Computing, 36-350"
date: "Wednesday September 28, 2016"
---

Returning more than one thing
===

When creating a function in R, though you cannot return more than one output, you can **return a list**. This (by definition) can contain an arbitrary number of arbitrary objects

```{r}
# Define some functions
identity.1 = function(x, y) { list(x, y) }
identity.2 = function(x, y) { list(x=x, y=y) }
identity.3 = function(x, y) { return(x, y) }

# Now let's run them
identity.1(1, 2)
identity.2(1, 2) # Notice the names (helpful)
identity.2(1, "2") # Notice the mixed data types
identity.2(1, 2:8) # Again, the mixed data types
```

Running the following code would produce an error:

```{r, error=TRUE}
identity.3(1, 2)
```

Another example with a returned list
===

```{r}
# get.wordtab: get a word table from text on the web
# Inputs:
# - str.url: string, specifying URL of a web page 
# - split: string, specifying what to split on. Default is the regex pattern
#   "[[:space:]]|[[:punct:]]"
# - tolower: boolean, TRUE if words should be converted to lower case before
#   the word table is computed. Default is TRUE
# - keep.numbers: boolean, TRUE if words containing numbers should be kept in
#   the word table. Default is FALSE
# Output: list, containing word table, and then some basic numeric summaries

get.wordtab = function(str.url, split="[[:space:]]|[[:punct:]]",
                       tolower=TRUE, keep.numbers=FALSE) {
  lines = readLines(str.url)
  text = paste(lines, collapse=" ")
  words = strsplit(text, split=split)[[1]]
  words = words[words != ""]
    
  # Convert to lower case, if we're asked to
  if (tolower) words = tolower(words)
  
  # Get rid of words with numbers, if we're asked to
  if (!keep.numbers)
    words = grep("[0-9]", words, inv=TRUE, val=TRUE)
    
  # Compute the word table
  wordtab = table(words)
  
  return(list(wordtab=wordtab,
              number.unique.words=length(wordtab),
              number.total.words=sum(wordtab)))
}
```

(Continued)
===

```{r}
# Trump's speech
trump.wordtab = get.wordtab("http://www.stat.cmu.edu/~ryantibs/statcomp-F16/data/trump.txt")
lapply(trump.wordtab, head)

# Clinton's speech
clinton.wordtab = get.wordtab("http://www.stat.cmu.edu/~ryantibs/statcomp-F16/data/clinton.txt")
lapply(clinton.wordtab, head)
```

Side effects
===

A **side effect** of a function is something that happens as a result of the function's body, but is not returned 

Examples:

- Printing something out to the console 
- Plotting something on the display 
- Saving an R data file, or a PDF, etc.

Example of a plotting side effect
===

```{r}
# get.wordtab: get a word table from text on the web
# Inputs:
# - str.url: string, specifying URL of a web page 
# - split: string, specifying what to split on. Default is the regex pattern
#   "[[:space:]]|[[:punct:]]"
# - tolower: boolean, TRUE if words should be converted to lower case before
#   the word table is computed. Default is TRUE
# - keep.numbers: boolean, TRUE if words containing numbers should be kept in
#   the word table. Default is FALSE
# - plot.wordtab: boolean, TRUE if word table should be plotted as a side 
#   effect. Default is FALSE
# Output: list, containing word table, and then some basic numeric summaries

get.wordtab = function(str.url, split="[[:space:]]|[[:punct:]]",
                       tolower=TRUE, keep.numbers=FALSE, plot.wordtab=FALSE) {
  lines = readLines(str.url)
  text = paste(lines, collapse=" ")
  words = strsplit(text, split=split)[[1]]
  words = words[words != ""]
    
  # Convert to lower case, if we're asked to
  if (tolower) words = tolower(words)
  
  # Get rid of words with numbers, if we're asked to
  if (!keep.numbers)
    words = grep("[0-9]", words, inv=TRUE, val=TRUE)
  
  # Compute the word table
  wordtab = table(words)
  
  # Plot the word table, if we're asked to
  if (plot.wordtab) plot(wordtab)
  
  return(list(wordtab=wordtab,
              number.unique.words=length(wordtab),
              number.total.words=sum(wordtab)))
}
```

(Continued)
===

```{r}
# Trump's speech
trump.wordtab = get.wordtab(
  "http://www.stat.cmu.edu/~ryantibs/statcomp-F16/data/trump.txt",
  plot=TRUE)
lapply(trump.wordtab, head)
```

Bad side effects
===

Not all side effects are desirable. One particularly **bad side effect** is if the function's body changes the value of some variable defined outside of the function

Not easy to do, but can be done and should be avoided! (We'll discuss function enviroments next time)