---
title: "More Examples"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{examples}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
error = TRUE
)
```
```{r setup}
library(Q7)
```
### Dogs
```{r}
Dog <- type(function(name, breed){
say <- function(greeting = "Woof!"){
cat(paste0(greeting,
" I am ", name, ", a ", breed,
".\n"))
}
})
```
```{r}
walter <- Dog("Walter", "Husky")
ls(walter)
```
```{r}
walter$say()
```
```{r}
max <- walter %>%
clone() %>%
implement({
name <- "Max"
})
max$say("Wussup Dawg!")
```
```{r}
max %>%
implement({
treats_eaten <- 0
eat_treat <- function(n = 1){
cat(paste(name, "eats", n, "treat(s).\n"))
treats_eaten <<- treats_eaten + n
}
}) %>%
implement({
is_satisfied <- function(){
treats_eaten > 5
}
})
```
```{r}
max$eat_treat()
max$is_satisfied()
max$eat_treat(2)
max$is_satisfied()
max$eat_treat(3)
max$is_satisfied()
```
```{r}
max$treats_eaten
```
```{r}
hasCollar <- feature({
Collar <- type(function(material, color){
description <- function() {
paste("is made of", material, "and in", color)
}
})
take_for_a_walk <- function(){
cat(name, "wears a collar that", collar$description(), "\n")
cat("We're gonna go out for a walk!")
}
})
```
```{r}
walter %>%
implement({
hasCollar()
collar <- Collar("metal", "red")
rm(Collar)
})
```
```{r}
walter$take_for_a_walk()
```
### Workplace Overtime
```{r}
Employee <- type(function(weekly_hours){}, "Employee")
john <- Employee(45)
```
```{r}
Manager <- type(function(weekly_hours){
extend(Employee)(weekly_hours)
final[is_manager] <- TRUE
}, "Manager")
mike <- Manager(45)
```
```{r}
hasOvertime <- feature_generic("hasOvertime")
hasOvertime.Employee <- feature({
is_overtime <- function() weekly_hours > 40
})
hasOvertime.Manager <- feature({
is_overtime <- function() FALSE
})
```
```{r}
john %>% hasOvertime()
john$is_overtime()
```
```{r}
mike %>% hasOvertime()
mike$is_overtime()
```
```{r}
hasOvertime.Boss <- feature({
final[is_overtime] <- function(){
FALSE
}
})
Boss <-
type({
extend(Employee)(24 * 7)
},
"Boss") %>%
hasOvertime()
jill <- Boss()
jill$is_overtime()
```
### Grade School Geometry
```{r}
Circle <- type(
function(radius){},
"Circle")
Square <- type(
function(side){},
"Square")
hasArea <- feature_generic("hasArea")
hasArea.Square <-
feature({
area <- function(){
side ^ 2
}
})
hasArea.Circle <-
feature({
area <- function(){
radius^2 * pi
}
})
```
```{r}
circle <- Circle(1) %>% hasArea()
circle$area()
square <- Square(1.5) %>% hasArea()
square$area()
```
```{r}
hasArea.EquilateralTriangle <- feature({
area <- function(){
(side^2 * sqrt(3)) / 4
}
})
EquilateralTriangle <- type(
function(side){},
"EquilateralTriangle") %>%
hasArea()
equilateral_triangle <- EquilateralTriangle(1)
equilateral_triangle$area()
```
### Locked
```{r}
isLocked <- feature({
lockEnvironment(.my, bindings = TRUE)
})
TestLocked <- type(function(){
a <- 1
}) %>% isLocked()
test_locked <- TestLocked()
try(test_locked$a <- 666)
try(test_locked$b <- 666)
try({
test_locked %>%
implement({
a <- 666
})
})
```
### State Machine
This simple state machine guards a secret message with a password.
```{r}
State <- type(
function(password, secret_message = ""){
name <- "DEFAULT"
cat("Processing Current State...\n")
print_current_state <- function(){
cat(paste("Current State:", name, "\n"))
}
})
LockedState <- State %>%
implement({
name <- "Locked"
print_current_state()
on_event <- function(event) {
if (event == password) {
cat("Access Granted.\n")
return(UnlockedState(password, secret_message))
} else {
cat("Wrong Password. Access Denied.\n")
return(.my)
}
}
})
UnlockedState <- State %>%
implement({
name <- "Unlocked"
print_current_state()
private[print_secret_message] <- function(){
cat(secret_message)
}
on_event <- function(event) {
if (event == password) {
return(LockedState(password, secret_message))
} else if (event == "show") {
print_secret_message()
return(.my)
} else{
cat("Invalid Instruction. \n")
return(.my)
}
}
})
SimpleDevice <- type(function(password, secret_message){
state <- LockedState(password, secret_message)
on_event <- function(event){
state <<- state$on_event(event)
}
})
```
```{r}
device <- SimpleDevice(password = "xxx",
secret_message = "I love you.")
device$on_event("1234")
device$on_event("PvmpKinM4n777")
device$on_event("xxx")
device$on_event("fiddlin...")
device$on_event("meddlin...")
device$on_event("show")
device$on_event("xxx")
device$on_event("0000")
```
#### Parameterized features?
_feature_ is subordinate to and dependent on _type_. It is encouraged to put all data members in a _type_ definition, while _feature_ mainly contain functions. If you feel significant need to parameterize a feature, think if it's better to create a nested object or to formally extend a type. You can always re-define something in a feature post hoc.
This will be implemented in the future.
```{r}
Word <- type(function(word){})
hasRepeat <- feature({
N_TIMES <- 2
repeat_word <- function(){
cat(rep(word, N_TIMES))
}
})
```
```{r}
apple <- Word("apple") %>% hasRepeat()
apple$repeat_word()
```
```{r}
pear <- Word("pear") %>%
implement({
hasRepeat()
N_TIMES <- 5
})
pear$repeat_word()
```
```{r}
repeatWordNTimes <- function(word, times){
localize(Word)(word) %>%
hasRepeat() %>%
implement({
N_TIMES <- times
})
}
orange <- repeatWordNTimes("orange", 7)
orange$repeat_word()
```
```{r}
isIterable <- feature_generic("isIterable")
isIterable.default <- feature({
forEach <- function(fn){
Vector(sapply(elementData, fn))
}
final[is_iterable] <- TRUE
})
isLocked <- feature({
lockEnvironment(.my, bindings = TRUE)
})
Vector <- type(function(elementData){
elementData <- elementData
elementCount <- length(elementData)
add <- function(e){
unlockBinding("elementData", .my)
unlockBinding("elementCount", .my)
elementData <<- c(elementData, e)
elementCount <<- length(elementData)
lockBinding("elementData", .my)
lockBinding("elementCount", .my)
invisible(.my)
}
remove <- function(index){
unlockBinding("elementData", .my)
unlockBinding("elementCount", .my)
elementData <<- elementData[-index - 1]
elementCount <<- length(elementData)
lockBinding("elementData", .my)
lockBinding("elementCount", .my)
invisible(.my)
}
clear <- function(){
unlockBinding("elementData", .my)
unlockBinding("elementCount", .my)
elementData <<- c()
elementCount <<- length(elementData)
lockBinding("elementData", .my)
lockBinding("elementCount", .my)
invisible(.my)
}
firstElement <- function(){
elementData[1]
}
lastElement <- function(){
elementData[elementCount]
}
}, "Vector") %>%
isIterable() %>%
isLocked()
nums <- Vector(c(1,2,3))
nums$elementData
nums$add(4)
nums$elementData
nums$elementCount
nums$remove(0)
nums$elementData
nums$clear()
nums$elementData
nums$elementCount
nums$add(c(554, 665, 776))
nums$elementData
nums$is_iterable <- FALSE
plus_one <- function(x){
x + 1
}
nums2 <- nums$
forEach(plus_one)$
remove(0)$
add(c(888, 999))
nums2$elementData
```
Microwave
```{r}
Microwave <- type(function(){
food <- NULL
put_food <- function(food){
if (!is.null(.my$food)) {
stop("There's already food.")
} else {
.my$food <- food
}
}
check_food <- function(){
if (is.null(food)) {
cat("Empty.\n")
} else {
cat(paste("The food is", food, "\n"))
}
}
heat <- function(seconds){
cat(paste(food,
"is heated for",
paste0(seconds, "s\n")))
}
remove_food <- function(){
food <<- NULL
}
})
microwave <- Microwave()
microwave$check_food()
microwave$put_food("chicken dinner")
microwave$put_food("meatballs")
microwave$heat(30)
microwave$remove_food()
microwave$put_food("meatballs")
microwave$check_food()
microwave$heat(40)
```