1

I'm coming from C++ background, trying to make use of it for R OOP programming with R6 package.
Consider the following typical situation when writing a large OOP code. - You have a class, in which you have several (possibly many) functions, each of which may also be quite complex and with many lines of code:

# file CTest.R

cTest <- R6Class(
  "CTest", 
  public = list(
    z = 10,
    fDo1 = function() {
      # very long and complex code goes here
      self$z <- self$z*2; self$z
      },
    fDo2 = function() { 
      # another very long and complex code goes here
     print(self) 
    }
  )
) #"CTest"

Naturally, you don't want to put ALL your long and various functions in the same (CTest.R) file - it will become messy and unmanageable.
If you program in C++, normal way to program such code is : first, you declare you functions in .h file, then you create .c files for each you complex function, where you define your function. This makes it possible to do collaborative code writing, including efficient source-control.

So, I've tried to do something similar in R, like: first, declaring a function as in code above, and then, trying to assign the "actual long and complex" code to it later (which later I would put in a separate file CTest-Do1.R):

cTest$f <- function() {      
  self$z <- self$z*100000; self$z
}

Now I test if it works:

> tt <- cTest$new(); tt; tt$fDo1(); tt
<CTest>
Public:
clone: function (deep = FALSE) 
fDo1: function () 
fDo2: function () 
z: 10
[1] 20
<CTest>
Public:
clone: function (deep = FALSE) 
fDo1: function () 
fDo2: function () 
z: 20

No, it does not.- As seen from output above, the function has not been changed.

Any advice?

IVIM
  • 2,167
  • 1
  • 15
  • 41
  • 2
    See https://stackoverflow.com/questions/26331030/dynamically-add-function-to-r6-class-instance – G. Grothendieck Jul 26 '17 at 15:49
  • 1
    "If you program in C++ (Java etc), normal way to program such code is : first, you declare you functions in .h file, then you create .c files for each you complex function, where you define your function" - that's not actually applicable to Java. It's not actually that common for a language to have separate header and implementation files. – user2357112 Jul 26 '17 at 15:53

2 Answers2

2

Thanks to Grothendieck's comment above, there's a reasonable workaround to make it work.

Instead of this:

# CTest-Do1_doesnotwork.R
cTest$fDo1 <- function() { 
    ... 
}     

write this:

# CTest-Do1_works.R  
cTest$set(
  overwrite = TRUE, "public", "fDo1",    
  function() {  
      ...
  }
)

This code can now be written in separate file, as originally desired.

I still wonder though - Is the above describe way actually the common(best) practice for writing large OOP codes in R community? (looks a bit strange to me).
If not, what is it (beyond just using source()) ? - so that to enable collaborative coding and source control for separate parts (functions) of a class ?

IVIM
  • 2,167
  • 1
  • 15
  • 41
1

I came here also searching for R6 best practice. One way that I've seen (here) is to define the functions elsewhere as normal R functions and pass in self, private etc as required

cTest<- R6::R6Class("CTest",
  public = list(

  fDo1 = function()
    cTestfDo1(self),

  fDo2 = function(x)
    cTestfDo2(self, private, x)
))

and else where have

cTestfDo1 <- function(self) {
  self$z <- self$z*2; self$z
}

and somewhere else

cTestfDo2 <- function(self, private, x) {
  self$z * private$q + x
}

etc

I don't know if it's best practice, or efficient, but the class definition looks neat with it and if the cTestfDo1 functions are not exported then it's relatively neat in the namespace too.

dougmet
  • 635
  • 4
  • 19