On 03/11/2019 6:43 p.m., Rolf Turner wrote:

On 4/11/19 10:31 AM, Duncan Murdoch wrote:

On 03/11/2019 4:11 p.m., Rolf Turner wrote:

I recently tried to write a new method for "[", to be applied to data
frames, so that the object returned would retain (all) attributes of the
columns, including attributes that my code had created.

I thrashed around for quite a while, and then got some help from Rui
Barradas who showed me how to do it, in the following manner:

`[.myclass` <- function(x, i, j, drop = if (missing(i)) TRUE else
length(cols) == 1)[{
      SaveAt <- lapply(x, attributes)
      x <- NextMethod()
      lX <- lapply(names(x),function(nm, x, Sat){
        attributes(x[[nm]]) <- Sat[[nm]]
        x[[nm]]}, x = x, Sat = SaveAt)
      names(lX) <- names(x)
      x <- as.data.frame(lX)
      x
}

If I set class(X) <- c("myclass",class(X)) and apply "[" to X (e.g.
something like X[1:42,]) the attributes are retained as desired.

OK.  All good.  Now we finally come to my question!  I want to put this
new method into a package that I am building.  When I build the package
and run R CMD check I get a complaint:

... no visible binding for global variable ‘cols’

And indeed, there is no such variable.  At first I thought that maybe
the code should be

`[.myclass` <- function(x, i, j, drop = if (missing(i)) TRUE else
                                         length(j) == 1)[{

But I looked at "[.data.frame" and it has "cols" too; not "j".

So why doesn't "[.data.frame" throw a warning when R gets built?

Can someone please explain to me what's going on here?

Defaults for parameters are evaluated in the evaluation frame of the
function, at the time the parameter is first used.

If you look at the source for "[.data.frame", you should see that "cols"
is defined there as a local variable.  The "drop" argument shouldn't be
used until it is.  (There's a call to "missing(drop)" early in the
source that doesn't count:  it doesn't evaluate "drop", it just checks
whether it is specified by the caller.)


OK.  As I understand what you're saying, the reason there isn't a
"no visible binding" problem in [.data.frame is that "cols" *is* defined
in the body of the function.  Whereas, in my method, "cols" does not get
defined anywhere in the function, and thus triggers the warning.

I guess that a workaround would be to do a dummy assignment, like unto
cols <- 42 at the start of the code for my method.

(a) Are there perils involved with this strategy?

Only that 42 might not be the right value.


(b) Is there anything wrong with my current strategy of replacing

     drop = if (missing(i)) TRUE else length(cols) == 1)

by

     drop = if (missing(i)) TRUE else length(j) == 1)

[.data.frame is pretty complicated, and I haven't read it closely enough to know if this is equivalent. I would suggest you consider not including "drop" at all, just implicitly including it in "..." .

Duncan Murdoch


???

As I said, this *seems* to work OK, by I cannot work through what the
implications might be.

Can anyone reassure me?

cheers,

Rolf


______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to