## ---- include =FALSE----------------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  errors = TRUE
)

## ----setup, include=FALSE-----------------------------------------------------
library(Q7)

## -----------------------------------------------------------------------------
TypeOne <- type(function(arg1, arg2){
  var1 <- 3
  add <- function(){
    arg1 + arg2 + var1
  }
})

## -----------------------------------------------------------------------------
type_one <- TypeOne(1, 2)
ls(type_one)
# There's no `arg1` or `arg2` seen
type_one$add()
# yet `add()` can see both arguments

## -----------------------------------------------------------------------------
type_one %>% implement({
  substract <- function(){
    arg1 - arg2
  }
})

## -----------------------------------------------------------------------------
TypeTwo <- type(function(){
  n <- 10
})

## -----------------------------------------------------------------------------
hasFeatureOne <- feature({
  x <- 1
  x_plus_n <- function(){
    x + n
  }
})

## -----------------------------------------------------------------------------
hasFeatureTwo <- feature({
  n <- 100 # Overwrites n from TypeTwo
  x <- 10 # Overwrites x from hasFeatureOne
  private[x_plus_n.old] <- x_plus_n 
    # Rename to preserve the old x_plus_n()
    # Mark private, because it is only going to be used by the new x_plus_n()
  x_plus_n <- function(){
    cat(sprintf("adding x (%i) to n (%i)...\n", x, n)) # do some extra thing
    x_plus_n.old() # call the old function
  }
})

## -----------------------------------------------------------------------------
type_two_with_features <- TypeTwo() %>% 
  hasFeatureOne() %>% 
  hasFeatureTwo()

type_two_with_features$x_plus_n()

## -----------------------------------------------------------------------------
Counter <- type(function(){
  private[count] <- 0
  
  add_one <- function(){
    count <<- count + 1 
    # Your IDE's syntax checker may alert you that 
    # `count` is not found in scope. 
    # You can safely ignore this.
  }
  
  get_count <- function(){
    count
  }
})

## -----------------------------------------------------------------------------
counter <- Counter()
ls(counter) # `count` can't be seen from the out side

counter$get_count() # but count can be read by domestic function
counter$add_one() # ... and be written to
counter$add_one()
counter$get_count() # when we read it again the number changes

## -----------------------------------------------------------------------------
exposePrivate <- feature({
  .my$pvt_env <- .private$.private  # `.private` contains a reference of itself with the same name, assigns it to `.my`
  #pvt_env <- .private # also works
})

counter %>% exposePrivate()
# .private reference appears in the object
ls(counter, all.names = TRUE)
counter$.private
counter$pvt_env$count # It is now possible to directly access any variable in the private environment