3

Suppose I have:

Foo <- R6::R6Class("Foo")
Bar1 <- R6::R6Class("Bar1", inherit = "Foo")
Bar2 <- R6::R6Class("Bar2", inherit = "Foo")

f <- Foo$new()

A. Can I do something like

R6::findChildren("Foo")
[1] "Bar1" "Bar2"

(I think this the same as R, R6, Get Full Class Name from R6Generator Object, but including it to be comprehensive)

B. Can I do something like

R6::findInstances("Foo")
[1] "f"

C. Can I do something like

b1 <- Bar1$new()
b2 <- Bar2$new()
R6::findInstances("Foo")
[1] "f" "b1" "b2"
Jack Tanner
  • 934
  • 1
  • 8
  • 24

2 Answers2

2

A am not aware of built-in functions in R6 that archieve these tasks.

There is however a way to write similar functionalities yourself by using members with reference semantics. The reason for that is that the reference mebers will be shared among all instances of the class as stated here

If your R6 class contains any fields that also have reference semantics (e.g., other R6 objects, and environments), those fields should be populated in the initialize method. If the field set to the reference object directly in the class definition, that object will be shared across all instances of the R6 objects.

In the following, I will only cover B. and C. since A. has already been answered here (as mentioned in the question).

Basic setup

You will have to add a member with reference semantics "directly in the class definition" and alter that member whenever a new instance is created.

library(R6)

foo <- R6Class(
  public = list(
    info = new.env(),                        # member with reference semantics
    initialize = function(ID){
      self$info$IDs = c(self$info$IDs, ID)   # "push_back" new ID
    }
  )
)

a_name <- foo$new("a_id")
b_name <- foo$new("b_id")

a_name$info$IDs
# [1] "a_id" "b_id"
b_name$info$IDs
# [1] "a_id" "b_id"

Notice that this code will give you instance IDs rather than instance names.

Inheritance

Inheriting this behavior is pretty straightforward by invoking the ID manager from the parent class (a.k.a. super class).

bar <- R6Class(
  inherit = foo,
  public = list(
    initialize = function(ID){
      super$initialize(ID)        # use ID management from the super class
    }
  )
)

c_name <- bar$new("c_id")
c_name$info$IDs
# [1] "a_id" "b_id" "c_id"

The list IDs will now contain all IDs for instances of either foo or bar.

A nice wrapper

If you want to get the IDs from the foo object rather than it's instances, the following can be used

# add a new "static" function to the R6Class/environment foo
foo$getIDs <- function(){
  dummy_instance <- foo$new(NULL)  # inserting NULL in an unnamed list does nothing
  dummy_instance$info$IDs
}

foo$getIDs()
# [1] "a_id" "b_id" "c_id"

I am aware this is not what you asked for since this appriach will give you IDs rather than names but for some purpuses this might be enough.

Gregor de Cillia
  • 7,397
  • 1
  • 26
  • 43
1

I think that this helper function does what you're looking for:

findR6_obj <- function(className=NULL){
    classList <- eapply(.GlobalEnv, class)
    obj_R6 <- classList[vapply(classList, function(ele) "R6" %in% unlist(ele), logical(1))]
    if (is.null(className)) {
        return(obj_R6)
    } else {
        names(obj_R6[vapply(obj_R6, function(ele) className %in% unlist(ele), logical(1))])
    }
}

If you use it without an argument, it'll return all R6 objects in the global environment (along with some more information about their class), and if you use it with an argument for className, say Foo, it'll return those R6 classes that include Foo.

You could modify this so that it only looks in some specific environment.

ricardo
  • 8,195
  • 7
  • 47
  • 69