[R-pkg-devel] Visible bindings and reference classes

luke-tierney at uiowa.edu luke-tierney at uiowa.edu
Tue Aug 11 22:01:06 CEST 2015


On Tue, 11 Aug 2015, William Dunlap wrote:

> You can avoid the temporary file by replacing
>  dput(def, file= (tf <- tempfile()))
>  compiler::cmpfile(tf)
> with
>  cdef <- compiler::compile(def)
>  #Note: no visible binding for '<<-' assignment to 'ConfigString'
> The compiled code appears to work.
>  eval(cdef)
>  c1 <- Config$new()
>  c1
>  #Reference class object of class "Config"
>  #Field "ConfigString":
>  #[1] "Hello, World!"
>  > objects(all=TRUE)
>  #[1] ".__C__Config"           ".__global__"
>  #[3] ".requireCachedGenerics" "c1"
>  #[5] "cdef"                   "Config"
>  #[7] "def"
>

Short answer: this isn't actually what is happening in Colin's
example, and in any case the notes seem OK to me, given what is
happening.

For the long answer, the basic issue is that the compiler, and
codetools, look at the code as it is written and try to make sense of
it. The methods implementation, and reference class implementation in
particular, rewrite the code in various ways. This creates some
mismatches. These can either we worked around by adapting
compiler/codetools to internals of methods/reference classes, or by
modifying methods/reference class implementations to be more amenable
to static analysis, or some combination.

The way packages are compiled already does adapt to the implementation
of methods/reference classes/etc to some degree by the way it compiles
code. It does not compile at the file level. Instead it compiles while
serializing code that has been loaded and in some cases modified by
the methods infrastructure, which is why the expression/file compile
example isn't related to what Colin was seeing. A reference class
definition like this at package top level should not be a problem for
byte compilation.

Here is a slight modification of Colin's example:

d1 = setRefClass("d1", fields=list(x = "numeric"))
a <- d1$accessors("x")

Then

> a$getX
function () 
x
<environment: 0x103c7e1f8>

and the environment of this function does not contain "x":
> codetools::checkUsage(a$getX)
<anonymous>: no visible binding for global variable ‘x’

When a packages using accessors is byte compiled the compiler sees
these incomplete accessor functions and points this out.

For an instance,

> v <- d1$new()
> v$getX
Class method definition for method getX()
function () 
x
<environment: 0x103ae3378>

This function has a new environment, the .xData part of v, and that does contain "x":

> codetools::checkUsage(v$getX)
# no note

So a change to the implementation of the accessors method to create
its accessors with an environment that is like the one they would see
when the are used would remove this note. I'm happy to help but
someone more familiar with reference class internals would have to
take the lead on this.

Compiled functions revert to interpreted when their environments are
changed, so the code does work, but doesn't benefit from compilation.
This is a bit overly cautious: if the structure of the environments in
terms of the variables they define remains the same, as it would if
the accessors created in the class had environments that matched their
intended usage, then the compiled code would remain valid and could
still be used. [Of course at present there isn't much if any benefit
to compiling functions this small, but that may change in the future.]







>
> Bill Dunlap
> TIBCO Software
> wdunlap tibco.com
>
> On Tue, Aug 11, 2015 at 8:47 AM, William Dunlap <wdunlap at tibco.com> wrote:
>
>> This is a problem in the compiler package.  Here is a way to reproduce it:
>>
>> def <- quote(Config <- setRefClass("Config",
>>     fields = list(
>>         ConfigString = "character"),
>>     methods = list(
>>         # Constructor
>>         initialize = function() {
>>             ConfigString <<- "Hello, World!"
>>         })
>> ))
>> dput(def, file= (tf <- tempfile()))
>> compiler::cmpfile(tf)
>> #Note: no visible binding for '<<-' assignment to 'ConfigString'
>> saving to file
>> #"C:\Users\wdunlap\AppData\Local\Temp\Rtmpk91qvT\file26d447c45b81.Rc" ...
>> done
>>
>>
>>
>>
>> Bill Dunlap
>> TIBCO Software
>> wdunlap tibco.com
>>
>> On Tue, Aug 11, 2015 at 4:24 AM, Martin Maechler <
>> maechler at stat.math.ethz.ch> wrote:
>>
>>> >>>>> Colin Gillespie <csgillespie at gmail.com>
>>> >>>>>     on Mon, 10 Aug 2015 20:33:32 +0000 writes:
>>>
>>> > Dear All,
>>> >
>>> > I have a package that uses reference classes. When I build the package I
>>> > get numerous notes of the sort
>>> >
>>> > Note: no visible binding for '<<-' assignment to 'pars'
>>> >
>>> > I've tried using GlobalVariables, but that didn't solve the issue.
>>>
>>> [ You mean globalVariables(): and it's a bad idea anyway IMO,
>>>   even if it is recommended : If you declare a variable in
>>>   there, it is "global" in all places in your package and the
>>>   codetools won't report it anywhere anymore.
>>>   Much better in my view is to use something like
>>>
>>>   var7 <- NULL # ~= globalVariables("var7")
>>>
>>> ]
>>>
>>> To your question:
>>>
>>> Reference classes are used in *many* places,  and the use of  ' <<- '
>>> is really "standard" there.
>>> e.g., package 'lme4', or 'pcalg' are two packages I'm involved with,
>>> which use ref.classes and ' <<- '  but are "fine" with that.
>>>
>>> So there must be something peculiar in your package leading to
>>> the  <<-  warnings.
>>>
>>> Maybe you should look into the source code of such other CRAN
>>> packages to see how "they" do it differently than you.
>>>
>>> Best regards,
>>> Martin
>>>
>>> Martin Maechler, ETH Zurich
>>>
>>>
>>> > After some googling, I came across the page
>>> > http://stackoverflow.com/q/23475309/203420 which suggests
>>> >
>>> > suppressBindingNotes <- function(variablesMentionedInNotes) {
>>> >   for(variable in variablesMentionedInNotes) {
>>> >     assign(variable,NULL, envir = .GlobalEnv)
>>> >   }
>>> > }
>>> > suppressBindingNotes(c("dat", "internal", "xmin", "pars", "no_pars"))
>>> >
>>> > But checking the package with --as-cran raises the note
>>> >
>>> > * checking R code for possible problems ... NOTE
>>> > Found the following assignments to the global environment:
>>> >   File ‘poweRlaw/R/aaa_all_classes.R’:
>>> >   assign(variable, NULL, envir = .GlobalEnv)
>>> >
>>> > What is the correct way of removing the "visible bindings" notes?
>>> >
>>> > Thanks
>>> >
>>> > Colin
>>> >
>>> >       [[alternative HTML version deleted]]
>>> >
>>> > ______________________________________________
>>> > R-package-devel at r-project.org mailing list
>>> > https://stat.ethz.ch/mailman/listinfo/r-package-devel
>>>
>>> ______________________________________________
>>> R-package-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-package-devel
>>>
>>
>>
>
> 	[[alternative HTML version deleted]]
>
> ______________________________________________
> R-package-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-package-devel

-- 
Luke Tierney
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:   luke-tierney at uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu


More information about the R-package-devel mailing list