As the topic describes I am looking for a way to achieve this:
require("R6")
R6cls <- R6::R6Class("R6obj",
public = list(val = 1, foo = function() "foo!")
)
# check this R6 class
r6o <- R6cls$new()
r6o
# <R6obj>
# Public:
# clone: function (deep = FALSE)
# foo: function ()
# val: 1
# now the S4 part
S4wR6slot <- function() new("S4wR6slot")
setClass("S4wR6slot", contains = "environment", # or maybe "R6" or "R6cls"? tried them all but none seemed to work
slots = list(a = "R6cls", b = "character"))
# Currently gives
Warning message:
undefined slot classes in definition of "S4wR6slot": a(class "R6cls")
# but you can still kind of use it
s4r6 <- S4wR6slot()
s4r6
# An object of class "S4wR6slot"
# <environment: 0x00000179de2da628>
# Slot "a":
# NULL
#
# Slot "b":
# character(0)
s4r6@b <- "text" # works nicely
# BUT trying to assign to that env slot
s4r6@a <- r6o
# will throw these "ugly" errors
Error in (function (cl, name, valueClass) :
c("assignment of an object of class “R6obj” is not valid for @‘a’ in an object of class “S4wR6slot”; is(value, \"R6cls\") is not TRUE",
"assignment of an object of class “R6” is not valid for @‘a’ in an object of class “S4wR6slot”; is(value, \"R6cls\") is not TRUE")
Playing around with setOldClass()
also did no good.
Maybe there is simply no way to make that work - just asking if someone has an idea? Or maybe even achieved this - otherwise maybe I did not rtfm well enough and one can point me to the documentation, where it says thou' shall not try to make this work?
CodePudding user response:
There is a way to have an R6 object inside an S4 class, but involves tricking the S4 system by defining an S4
class called 'R6'. This will prevent the methods
package complaining that class R6 doesn't exist. Fortunately, it doesn't actually check whether the 'R6' object in the prototype is of the S4 type, allowing you to stick an actual R6 object in there.
library(R6)
R6cls <- R6::R6Class("R6obj",
public = list(val = 1, foo = function() "foo!")
)
setClass('R6')
setClass("S4wR6slot", slots = list(a = 'R6', b = "character"),
prototype = list(a = R6cls$new(), b = 'Hello'))
S4wR6slot <- function() new("S4wR6slot")
myS4 <- S4wR6slot()
class(myS4)
#> [1] "S4wR6slot"
#> attr(,"package")
#> [1] ".GlobalEnv"
isS4(myS4)
#> [1] TRUE
myS4@a
#> <R6obj>
#> Public:
#> clone: function (deep = FALSE)
#> foo: function ()
#> val: 1
CodePudding user response:
I have also found a solution for this simple example class that seems to work - BUT SADLY that solution interestingly failed/fails for more complex R6 classes.
Adding that example solution here for completness
require(R6)
R6cls <- R6::R6Class("R6obj",
public = list(val = 1, foo = function() "foo!")
)
# check this R6 class
r6o <- R6cls$new()
r6o
# <R6obj> # <- I SUDDENLY NOTICED THIS on a second look!
# Public:
# clone: function (deep = FALSE)
# foo: function ()
# val: 1
S4wR6slot <- function() new("S4wR6slot")
setClass("S4wR6slot", contains = "environment",
slots = list(a = "R6obj" , b = "character"))
# list(a = "R6obj" ... is what did the "magic"
s4r6 <- S4wR6slot()
s4r6
# An object of class "S4wR6slot"
# <environment: 0x000002520292f470>
# Slot "a":
# NULL
#
# Slot "b":
# character(0)
s4r6@b <- "text"
s4r6@a <- r6o # THIS THEN WORKED/WORKS!
class(r6o)
# [1] "R6obj" "R6" # I simply used that "R6obj" in the S4 definition above
is(r6o, "R6")
# [1] TRUE
is(r6o, "R6obj")
# [1] TRUE
But somehow that "Robj" class (type) gets lost in more complex settings ie I am using a R6 class defined in one package in another package and then that "R6obj" is no longer available for usage. :-(