3

Can I create an S4 superclass of "function" and access the slots of that object from the function call? At the moment I have:

> setClass("pow",representation=representation(pow="numeric"),contains="function") [1] "pow" > z=new("pow",function(x){x^2},pow=3) > z(2) [1] 4 

Now what I really want is for the function to be x to the power of the @pow slot of itself, so if I then do:

> z@pow=3 

I get cubes, and if I do:

> z@pow=2 

I get squares.

But I don't see how to get a reference to 'self' like I would do in Python. I'm guessing its somewhere in the environment somewhere...

Here's how it works in python:

class Pow: def __init__(self,power): self.power=power self.__call__ = lambda x: pow(x,self.power) p = Pow(2) # p is now a 'squarer' print p(2) # prints 4 p.power=3 # p is now a 'cuber' print p(2) # prints 8 

Couldn't really be easier, and I didn't even have to do "import antigravity"....

6
  • I think you probably want to use a reference class Commented Dec 2, 2011 at 2:00
  • Yeah? Has the S language finally got object-oriented programming right this time? Commented Dec 2, 2011 at 8:21
  • If by right, you mean has implemented in a way that you're familiar with from languages like java, then yes. Commented Dec 2, 2011 at 13:00
  • I meant in the way that S3 is clearly wrong (but its a very moby hack) and S4 is just unclearly wrong (see above). But yeah, I think in the limit as t->Inf then R->python... Lets get rid of curly braces from R and use indentation.... Commented Dec 2, 2011 at 13:51
  • With reference classes you'd get 'self' but loose the 'isA' relationship Spacedman asked for (at least in my experiments -- a more complete example?). Also you'd have reference semantics on your pow exponent, which could be quite confusing though consistent with the python implementation. Commented Dec 2, 2011 at 14:40

3 Answers 3

3

Resorting to a little language manipulation

setClass("Pow", representation("function", pow="numeric"), prototype=prototype( function(x) { self <- eval(match.call()[[1]]) x^self@pow }, pow=2)) 

and then

> f = g = new("Pow") > g@pow = 3 > f(2) [1] 4 > g(2) [1] 8 

although as Spacedman says things can go wrong

> f <- function() { Sys.sleep(2); new("Pow") } > system.time(f()(2)) user system elapsed 0.002 0.000 4.005 

A little more within the lines but deviating from the problem specification and probably no less easy on the eyes is

setClass("ParameterizedFunFactory", representation(fun="function", param="numeric"), prototype=prototype( fun=function(x, param) function(x) x^param, param=2)) setGeneric("fun", function(x) standardGeneric("fun")) setMethod(fun, "ParameterizedFunFactory", function(x) x@fun(x, x@param)) 

with

> f = g = new("ParameterizedFunFactory") > g@param = 3 > fun(f)(2) [1] 4 > fun(g)(2) [1] 8 
Sign up to request clarification or add additional context in comments.

2 Comments

I might just give you that. Although if you try and do an anonymous object: new("Pow")(3) it actually gets the \@pow slot from another new object created by the eval rather than the one created by the initial "new" call. Not that it makes any difference, and its a very perverse thing to do anyway. eval is nearly always evil.
Shudder. You are making my eyes bleed.
0

I think it depends what you really want. Is this implementation any closer to your goal?

setClass("pow",representation=representation(pow="numeric"),contains="function") z=new("pow",function(x, pow=3){x^pow}) > z(2) [1] 8 z(2,4) #[1] 16 

Comments

0

It seems that the parent function can be accessed via sys.function.

setClass("pow", slots = c(pow = "numeric"), contains = "function") z <- new("pow", function (x) x^(sys.function()@pow), pow = 2) z(6) # [1] 36 z@pow <- 3 z(6) # [1] 216 

I don't know whether sys.function exists when this question was firstly discussed, though.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.