Threading state

In S3 the challenge is to return a value and modify the object.

new_stack <- function(items = list()) {
  structure(list(items = items), class = "stack")
}

push <- function(x, y) {
  x$items <- c(x$items, list(y))
  x
}

No problem with that, but what about when we want to pop a value? We need to return two things.

pop <- function(x) {
  n <- length(x$items)
  
  item <- x$items[[n]]
  x$items <- x$items[-n]
  
  list(item = item, x = x)
}

The usage is a bit awkward:

s <- new_stack()
s <- push(s, 10)
s <- push(s, 20)

out <- pop(s)
# Update state:
s <- out$x

print(out$item)
#> [1] 20

In python and other languages we have structured binding to make this less awkward. R has the {zeallot} package. For more, see this vignette:

vignette('unpacking-assignment')

However, this is all easier in R6 due to the reference semantics!

Stack <- R6::R6Class("Stack", list(
  items = list(),
  push = function(x) {
    self$items <- c(self$items, x)
    invisible(self)
  },
  pop = function() {
    item <- self$items[[self$length()]]
    self$items <- self$items[-self$length()]
    item
  },
  length = function() {
    length(self$items)
  }
))

s <- Stack$new()
s$push(10)
s$push(20)
s$pop()
#> [1] 20