3

I have written a stack "class" with the following functions: add, push, pop, size, isEmpty, clear (and some more).

I'd like to use this "class" as a generic in R, so I may create multiple instances of stacks within my script. How do I go about doing this?

(I have class in quotes because my stack functions are written in a different script (not necessarily the definition of a class per se)

Thanks in advance

list <- ""
cursor = 0

#Initializes stack to empty
stack <- function(){
list <- c()
cursor = -1

assign("list",list,.GlobalEnv)
assign("cursor",cursor,.GlobalEnv)
}


#Where item is a item to be added to generic list
push <- function(item){
if(size(list) == 0){
    add(item, -1)
}else{
    add(item, 0)        
}
assign("list",list,.GlobalEnv)
}
laemtao
  • 147
  • 11
  • There really not much to go on in this question. A bit of code example will be useful. – Sam Jan 23 '13 at 19:55
  • Have you tried googling "R S4 classes" and reading the manuals and guides that pop up? – David Robinson Jan 23 '13 at 19:56
  • @DavidRobinson I haven't looked in to S4 Classes because I am not sure I need them. In this case, is that style necessary? Thank you – laemtao Jan 23 '13 at 20:00
  • This question appears to be what you're looking for (and should thus be closed as a duplicate): http://stackoverflow.com/questions/9521651/r-and-object-oriented-programming – David Robinson Jan 23 '13 at 20:01
  • @laemtao, your best bet at keeping this question open is to provide some code. – GSee Jan 23 '13 at 20:02
  • Thanks everyone! Reviewing answers. Hope this question helped those with similar inquires. – laemtao Jan 23 '13 at 22:20

2 Answers2

5

This is a simpler version of the stack implementation @GSee references that avoids using any of the formal object-orientation systems available in R. Simplification proceeds from the fact that all functions in R are closures and functions created during a function call are bound to the environment created for that call.

new_stack <- function() {
    stack <- vector()
    push <- function(x) stack <<- c(stack, x)
    pop <- function() {
        tmp<-tail(stack, 1)
        stack<<-stack[-length(stack)]
        return(tmp)
    }
    structure(list(pop=pop, push=push), class='stack')
}

x <- new_stack()
x$push(1:3)
x$pop()
# [1] 3
x$pop()
# [1] 2

Here's an S4 implementation, for comparison.

setClass('Stack', 
         representation(list='list', cursor='numeric'),  # type defs
         prototype(list=list(), cursor=NA_real_))        # default values

setGeneric('push', function(obj, ...) standardGeneric('push'))
setMethod('push', signature(obj='Stack'), 
    function(obj, x) {
        obj@list <- c(x, obj@list)
        obj
})

setGeneric('pop', function(obj, ...) standardGeneric('pop'))
setMethod('pop', signature(obj='Stack'),
    function(obj) {
        obj@cursor <- obj@list[[1]]
        obj@list <- obj@list[-1]
        obj
    }
)

x <- new('Stack')

# cursor is empty to start
x@cursor
#[1] NA

# add items
x <- push(x, 1)
x <- push(x, 2)

# pop them (move next item to cursor, remove from list)
x <- pop(x)
x@cursor
# [1] 2
x <- pop(x)
x@cursor
# [1] 1
Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
  • The use of `on.exit` is a bit clumsy (and unnecessary). – hadley Jan 24 '13 at 13:34
  • @hadley thanks for your comments. rather than the usual tmp-remove-return, I thought I'd exercise some creativity. sorry to displease. do you mean it's clumsy in terms of readability? I would discourage such an action in a longer function, but here it seemed pretty harmless. – Matthew Plourde Jan 24 '13 at 14:41
  • What are alternatives to on.exit? (still learning S4 mannerisms and conventions) – laemtao Jan 24 '13 at 15:26
  • @laemtao see the definition of `stack@push` in @GSee's answer. – Matthew Plourde Jan 24 '13 at 15:31
  • @MatthewPlourde it's clumsy in that you usually see `on.exit` used to ensure something happens if the function exits with an error - so when I saw it, I immediately started trying to figure out what would throw an error. – hadley Jan 24 '13 at 15:39
  • @hadley I've encountered `on.exit` on only a few occasions in my short time with R, and didn't perceive how this usage might be misleading. Brevity may be the soul of wit, but clarity is the spirit of cooperation! Edited accordingly. – Matthew Plourde Jan 24 '13 at 15:49
3

Since you are specifically talking about a stack "class" with push and pop methods, here's an implementation by Jeff Ryan taken from Introducing Closures which you can read for an explanation of what's going on here.

new_stack <- function() { 
  stack <- new.env()
  stack$.Data <- vector()
  stack$push <- function(x) .Data <<- c(.Data,x)
  stack$pop  <- function() {
    tmp <- .Data[length(.Data)]
    .Data <<- .Data[-length(.Data)]
    return(tmp)
  }
  environment(stack$push) <- as.environment(stack)
  environment(stack$pop) <- as.environment(stack)
  class(stack) <- "stack"
  stack
}

> x <- new_stack()
> x$push(1:3)
> x$pop()
[1] 3
> x$pop()
[1] 2

Then, if you create S3 generics...

push <- function(x, value, ...) UseMethod("push")
pop  <- function(x, ...) UseMethod("pop")
push.stack <- function(x, value, ...) x$push(value)
pop.stack  <- function(x) x$pop()

> push(x, 5)
> pop(x)
[1] 5
> pop(x)
[1] 1
GSee
  • 48,880
  • 13
  • 125
  • 145