---
title: "Introduction to Modules"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{introduction}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

## Use
The `mod` package is designed to be used either attached or unattached to your search path.

The following demonstrations show the package attached:
```{r}
require(mod)
```

## Examples

Define an inline module:
```{r}
my <- module({
        a <- 1
        b <- 2
        f <- function(x, y) x + y
})
```

The resulting module contains the objects defined within.
```{r}
ls(my)
```

Subset the module to access its objects.
```{r}
my$a
my$b
my$f(my$a, my$b)
```

Use `with()` to aceess the objects with their bare names.
```{r}
with(my, 
     f(a,b))
```


### Attach a Module to the Search Path

Just like a package, a module can be attached to the search path.
```{r}
use(my)
```

The `my` module is attached to the search path as "module:my".
```{r}
search()
```

And you can use the objects inside directly, just like those from a package.
```{r}
f(a,b)
```

Detach the module from the search path when done, if desired.
```{r}
drop("my")
```

### Make objects Available to another Module

Use `refer()` to "copy" objects from another module. In the following example, we create a new module `my_other` that uses the objects from `my`, which is previsouly defined. 
```{r}
ls(my)

my_other<- module({
        refer(my)
        c <- 4
        d <- 5
        f <- function() print("foo") 
})

ls(my_other)
my_other$f()
```
In addition to its own objects, `my_other` module has all objects from `my`, except `f`: because `my_other` module also has a `f` object, and replaces the `f` from `my` module.

We can re-define `my_other` and prepend objects from `my`  with _my_. This way, both `f`s are available. 
```{r}
my_other <- module({
        refer(my, prefix = .)
        c <- 4
        d <- 5
        f <- function() print("foo") 
})

ls(my_other)

my_other$my.f(1, 2)
my_other$f()
```


### Public and Private Variables
   
A variable is _private_ if its name starts with `..`.
```{r}
room_101 <- module({
        ..diary <- "Dear Diary: I used SPSS today..."
        get_diary <- function(){
                ..diary
        }
})
```


A private variable cannot be seen or touched. There is no way to directly access `..diary` from the outside, except by a function defined within the module, `get_diary()`. This can be useful if you want to shield some information from the other users or programs.
```{r}
ls(room_101)
room_101$..diary
room_101$get_diary()
```

If using `provide()` function to explicitly declair public variables, all others become private.
```{r}
room_102 <- module({
        provide(open_info, get_classified)
        
        open_info <- "I am a data scientist."
        classified_info <- "I can't get the database driver to work."
        get_classified <- function(){
                classified_info
        }
})

ls(room_102)
room_102$open_info
room_102$classified_info
room_102$get_classified()
```
    
### Use a package
The `mod` package provides a `require()` function. `mod:::require()` works in the same manner as do `base::require()`, but makes a packages available for use in its containing module only.
```{r eval = FALSE}
mpg_analysis <- module({
    require(ggplot2)
    plot <- qplot(mtcars$mpg)    
})
mpg_analysis$plot
```

Meanwhile, the global search path remain unaffected, not containing the `ggplot2` package:
```{r}
"package:ggplot2" %in% search()
```


`mod::ule` is simple, lightweight and staright-forward. It is plain R and contains zero GMO. 


Modules live any any other R object.

You do things the R way. For example, `acquire()` and `module()` only returns a module object; It is up to you to put it into your working environemnt with `<-`.d 


    
### Simulate OOP

In this example, Bobby gets hungry, Dad complains and calls Mom:
```{r}
bobby <- mod::ule({
        age_now <- 14
        favorite_food <- c("hamburger", "pizza", "chow mein")
        hungry_for <- function() {
          set.seed(Sys.Date())
          sample(favorite_food, 1)
        }
        cry <- function(){
                sprintf("I just really really want some %s, now!!!", hungry_for())
        }
})

dad <- mod::ule({
        refer(bobby, prefix = .)
        provide(complain, call_mom)
        complain <- function(){
                sprintf("When I was %d, I've already earned a living on the dock.",
                        bobby.age_now)
        }
        call_mom <- function(){
                sprintf("Honey, can you stop by the convenience store and get some %s?", 
                        bobby.hungry_for())
        }
})
```

```{r}
bobby$cry()
dad$complain()
dad$call_mom()
```

It is imperative that `mod` be only adopted in simple cases; no mutable state is allowed in modules. If full-featured OOP is desired, use [`R6`](https://CRAN.R-project.org/package=R6). The user is reminded that OOP, in general, should be used sparingly and with deliberation.

## Notes

#### Environment

A module _is_ an environment. This means that every rule that applies to environments, such as copy-by-reference, applies to modules as well.
```{r}
mode(my)
is.environment(my)
```


#### Terms
Some may wonder the choice of terms. Why `refer()` and `provide()`? Further, why not `import()` and `export()`? This is because we feel _import_ and _export_ are used too commonly, in both R, and other popular languages with varying meanings. The popular [`reticulate`](https://CRAN.R-project.org/package=reticulate) package also uses `import()`. To avoid confusion, we decided to introduce some synonyms. With analogous semantics, [`refer()`](https://clojuredocs.org/clojure.core/refer) is borrowed from Clojure, while [`provide()`](https://docs.racket-lang.org/reference/require.html?q=provide#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._provide%29%29) from Racket; Both languages are R's close relatives.

#### Locked

A module is locked by default. It is impossible to either change the value of a object or add a new object to a module. 
```{r error = TRUE}
my$a <- 1
my$new_var <- 1
```

#### Hidden Objects

As a general R rule, names that start with `.` define hidden objects.
```{r}
my_yet_another <- module({
        .var <- "I'm hidden!"
})
```

Hidden objects are not returned by `ls()`, unless specified.
```{r}
ls(my_yet_another)
ls(my_yet_another, all.names = TRUE)
```

Nonetheless, in a module, they are treated the same as public objects.
```{r}
my_yet_another$.var
```

#### Load/Attach from File

```{r}
module_path <- system.file("misc/example_module.R", package = "mod")
```

To load and assign to object: 
```{r}
example_module <- acquire(module_path)
ls(example_module)
example_module$a
example_module$d()
example_module$e(100)
```

To load and attach to search path:
```{r}
use(module_path)
ls("module:example_module")
a
d()
e(100)
```


#### Modules and Packages

As it could be confusing how to deal with modules and packages, the following clarification is made:

- Attach a Package
  - To the local "search path", at module context: `require()`
  - To the global search path, at global environment: `require()`
  
- Attach a Module
  - To another module's local "search path": not available\*
  - To the global search path: `use()`

- Copy Objects from a Module
  - To another module: `refer()`
  - To the global environment: not available\*\*

- Use Modules inside a Package?
  - Yes, the package must `Depends` or `Imports` the `mod` package


\*: Modules cannot be attached to another module's "seach path". Use `refer()` instead to make clearly visible objects in the module context. 
\*\*:  Objects cannot be batch-copied from a module to the global environment, use `use()` to attach the module to the global search path in order to use them directly. 

These two features seek to avoid one very important problem `mod` packages intends to solve: conflicting names. 



#### Unattached
As aforementioned, the package is designed to be usable both attached and unattached.

If you use the package unattached, you must always qualify the object name with `::`, such as `mod::ule()`, a shorthand for `mod::module()`. However, while inside a module, the `mod` package is always available, so you do not need to use `::`. Note that in the following example, `provide()` inside the module expression is unqualified.

See:
```{r}
detach("package:mod")

my_mind <- mod::ule({
  provide(good_thought)
  good_thought <- "I love working on this package!"
  bad_thought <- "I worry that no one will appreciate it."
})

mod::use(my_mind)
good_thought
```
