r-lib / R6

Encapsulated object-oriented programming for R
https://R6.r-lib.org
Other
405 stars 56 forks source link

Bytecode is lost during initialization #113

Closed mllg closed 7 years ago

mllg commented 7 years ago

Hi there,

If you add bytecode-compiled functions to a class (or let R handle it by setting ByteCompile: yes in the DESCRIPTION), the byte code is lost during initialization.

Example:

library(R6)

MyClass = R6Class("MyClass", public = list())
MyClass$set("public", "fun", compiler::cmpfun(function(x) x^2))
print(MyClass$public_methods$fun)

myclass = MyClass$new()
print(myclass$fun)

This should either be fixed or clearly documented.

wch commented 7 years ago

It looks like this happens because when you change the environment of a compiled function, it loses the BCODESXP. It would be nice if there were a way to change the environment without losing that.

For example:

# Compile function in a local env because if CLOENV is the global env, it
# appears a bit differently with .Internal(inspect()).
f <- local({
  compiler::cmpfun(function(x) x^2))
})

# Duplicate compiled function and assign new env
f2 <- f
environment(f2) <- new.env()

.Internal(inspect(f))
.Internal(inspect(f2))

The resulting output for f and f2:

> .Internal(inspect(f))
@10dedec98 03 CLOSXP g0c0 [NAM(2),ATT] 
FORMALS:
  @10dedf3f0 02 LISTSXP g0c0 [] 
    TAG: @1028716d0 01 SYMSXP g1c0 [MARK,NAM(2)] "x"
    @10281bf08 01 SYMSXP g1c0 [MARK,NAM(2)] "" (has value)
BODY:
  @10dedf188 21 BCODESXP g0c0 [NAM(2)] 
CLOENV:
  @10ccc9320 04 ENVSXP g0c0 [NAM(2)] <0x10ccc9320>
ATTRIB:
  @10deded08 02 LISTSXP g0c0 [] 
    TAG: @102825390 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x4000] "srcref" (has value)
    @10bf511b8 13 INTSXP g0c3 [OBJ,NAM(2),ATT] (len=8, tl=0) 1,29,1,43,29,...
    ATTRIB:
      @10cccac70 02 LISTSXP g0c0 [] 
    TAG: @102825400 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x4000] "srcfile" (has value)
    @10cccaa78 04 ENVSXP g0c0 [OBJ,ATT] <0x10cccaa78>
    FRAME:
      @10cccb178 02 LISTSXP g0c0 [] 
        TAG: @104aa4508 01 SYMSXP g1c0 [MARK,NAM(2)] "lines"
        @10cf14598 16 STRSXP g0c1 [] (len=1, tl=0)
          @10ce738d8 09 CHARSXP g0c4 [gp=0x60,ATT] [ASCII] [cached] "f <- local(compiler::cmpfun(function(x) x^2))
"
        TAG: @104aad508 01 SYMSXP g1c0 [MARK] "filename"
        @10cf14568 16 STRSXP g0c1 [] (len=1, tl=0)
          @10281c6c8 09 CHARSXP g1c1 [MARK,gp=0x60] [ASCII] [cached] ""
    ENCLOS:
      @1028552d8 04 ENVSXP g1c0 [MARK,NAM(2)] <R_EmptyEnv>
    ATTRIB:
      @10ccca208 02 LISTSXP g0c0 [] 
        TAG: @10281bd48 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x4000] "class" (has value)
        @10bf52ae0 16 STRSXP g0c2 [NAM(2)] (len=2, tl=0)
          @104831f50 09 CHARSXP g1c2 [MARK,gp=0x61] [ASCII] [cached] "srcfilecopy"
          @10281c278 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "srcfile"
    TAG: @10281bd48 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x4000] "class" (has value)
    @10cf14508 16 STRSXP g0c1 [] (len=1, tl=0)
      @10281c248 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "srcref"
> .Internal(inspect(f2))
@10cc4af48 03 CLOSXP g0c0 [NAM(2),ATT] 
FORMALS:
  @10dedf3f0 02 LISTSXP g0c0 [] 
    TAG: @1028716d0 01 SYMSXP g1c0 [MARK,NAM(2)] "x"
    @10281bf08 01 SYMSXP g1c0 [MARK,NAM(2)] "" (has value)
BODY:
  @10db2d6d8 06 LANGSXP g0c0 [NAM(2)] 
    @10282bdf8 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x5000] "^" (has value)
    @1028716d0 01 SYMSXP g1c0 [MARK,NAM(2)] "x"
    @10cf0dac8 14 REALSXP g0c1 [NAM(2)] (len=1, tl=0) 2
CLOENV:
  @10cc4aed8 04 ENVSXP g0c0 [NAM(1)] <0x10cc4aed8>
ATTRIB:
  @10cc4af80 02 LISTSXP g0c0 [] 
    TAG: @102825390 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x4000] "srcref" (has value)
    @10bf511b8 13 INTSXP g0c3 [OBJ,NAM(2),ATT] (len=8, tl=0) 1,29,1,43,29,...
    ATTRIB:
      @10cccac70 02 LISTSXP g0c0 [] 
    TAG: @102825400 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x4000] "srcfile" (has value)
    @10cccaa78 04 ENVSXP g0c0 [OBJ,ATT] <0x10cccaa78>
    FRAME:
      @10cccb178 02 LISTSXP g0c0 [] 
        TAG: @104aa4508 01 SYMSXP g1c0 [MARK,NAM(2)] "lines"
        @10cf14598 16 STRSXP g0c1 [] (len=1, tl=0)
          @10ce738d8 09 CHARSXP g0c4 [gp=0x60,ATT] [ASCII] [cached] "f <- local(compiler::cmpfun(function(x) x^2))
"
        TAG: @104aad508 01 SYMSXP g1c0 [MARK] "filename"
        @10cf14568 16 STRSXP g0c1 [] (len=1, tl=0)
          @10281c6c8 09 CHARSXP g1c1 [MARK,gp=0x60] [ASCII] [cached] ""
    ENCLOS:
      @1028552d8 04 ENVSXP g1c0 [MARK,NAM(2)] <R_EmptyEnv>
    ATTRIB:
      @10ccca208 02 LISTSXP g0c0 [] 
        TAG: @10281bd48 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x4000] "class" (has value)
        @10bf52ae0 16 STRSXP g0c2 [NAM(2)] (len=2, tl=0)
          @104831f50 09 CHARSXP g1c2 [MARK,gp=0x61] [ASCII] [cached] "srcfilecopy"
          @10281c278 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "srcfile"
    TAG: @10281bd48 01 SYMSXP g1c0 [MARK,NAM(2),LCK,gp=0x4000] "class" (has value)
    @10cf14508 16 STRSXP g0c1 [] (len=1, tl=0)
      @10281c248 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "srcref"
wch commented 7 years ago

It could be an option to compile functions in R6 objects.

hadley commented 7 years ago

There's no way to preserve, but you could check for the presence of bytecode, and re-compile if found.

wch commented 7 years ago

@hadley I don't know much about how the compiled code works, but it seems to me that if you reassign the environment of a function, it shouldn't be necessary to remove the compiled version. But that would require a change in R itself.

I suspect the overhead of re-compiling on instantiation wouldn't generally be worth it, especially because R's JIT is now enabled by default.

hadley commented 7 years ago

@wch it has to be recompiled because you've potentially changed the lookup of objects (which the bytecode might (or might in the future) cache)