Skip to content

Is it Possible to Create S4 Function Objects?

5 messages · Hervé Pagès, Abby Spurdle

#
Dear All,

I was wondering if it's possible to create S4 function objects?
(Or S4 closures, if you prefer).

i.e.
An R object, that is both an S4 object, and a function.

This would allow one to write:
I've searched for this, but I can't find any examples.

If it's possible, then that leads to the question of if/how the body
of f() could directly access the value of the slot?
I should note that the more common approach of storing values in a
function's environment, doesn't work well for top-level objects.
This approach is dependent on immutability of the function's data, and
I'm reluctant to create such constraints.
3 days later
#
It appears that my previous post may lack clarity.

So, I've created three examples of mathematical function objects.
(One) using a standard closure with lexical scoping, (two) using S3
with an attribute and (three) using S4 with a slot.
Each example constructs the function object via a constructor (of some
form), plots it, then prints the attribute/etc.
However, the third example with S4 is incomplete.

Any suggestions welcome.

----begin code----

plotf <- function (f)
{   x <- seq (-1, 1,, 200)
    plot (x, f (x), type="l")
}

#standard closure, with lexical scoping
quad.lex <- function (p = c (0, 0, 1) )
{   function (x)
        p [1] + p [2] * x + p [3] * x^2
}

#s3-based function object, with attribute
quad.s3 <- function (p = c (0, 0, 1) )
{   f <- function (x)
    {   this <- sys.function ()
        p <- attr (this, "p")
        p [1] + p [2] * x + p [3] * x^2
    }
    attr (f, "p") <- p
    f
}

#s4-based function object, with slot
setClass ("Quad.S4", slots = list (p="numeric") )
Quad.S4 <- function (p = c (0, 0, 1) )
{   #?
}

f.lex <- quad.lex ()
plotf (f.lex)
environment (f.lex)$p

f.s3 <- quad.s3 ()
plotf (f.s3)
attr (f.s3, "p")

f.s4 <- Quad.S4 ()
#plotf (f.s4)
#f.s4 at p


On Sat, Feb 13, 2021 at 10:53 AM Abby Spurdle (/??bi/)
<spurdle.a at gmail.com> wrote:
5 days later
#
Hi Abby,

Something along the line of:

   setClass("S4Function",
     contains="function",
     representation(name="character", more_stuff="ANY")
   )

seems to do what you want:

   f <- new("S4Function", function(a) a^2, name="square")

   # 'f' is both an S4 object and a function:
   is.object(f)
   # [1] TRUE
   is.function(f)
   # [1] TRUE

   f at name
   # [1] "square"
   f(11)
   # [1] 121

Hope this helps,

H.
On 2/12/21 1:53 PM, Abby Spurdle (/??bi/) wrote:

  
    
#
Oh wow.
Post of the year!
Where's the like button?

Note, I was able to rewrite it without the deprecated args.
(Don't want one of those CRAN emails, in 12 months from now, saying
please change XXXX).

I'll have to come back to this later, to see if I can get the body of
f() to access the slot
On Mon, Feb 22, 2021 at 11:36 AM Herv? Pag?s <hpages.on.github at gmail.com> wrote:
2 days later
#
I've completed the S4 example.
Thank you, Herve, for your assistance.

----begin code----
plotf <- function (f)
{   x <- seq (-1, 1,, 200)
    plot (x, f (x), type="l")
}

#s4-based function object, with slot
setClass ("Quad.S4", contains="function", slots = list (p="numeric") )
Quad.S4 <- function (p = c (0, 0, 1) )
{   f <- function (x)
    {   this <- sys.function ()
        p <- this at p
        p [1] + p [2] * x + p [3] * x^2
    }
    new ("Quad.S4", f, p=p)
}

f.s4 <- Quad.S4 ()
plotf (f.s4)
f.s4 at p


On Tue, Feb 23, 2021 at 11:23 AM Abby Spurdle (/??bi/)
<spurdle.a at gmail.com> wrote: