--- 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) ```