[Rd] Puzzled about a new method for "[".

Rolf Turner r@turner @end|ng |rom @uck|@nd@@c@nz
Mon Nov 4 00:43:56 CET 2019


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?

(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)

???

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

Can anyone reassure me?

cheers,

Rolf

-- 
Honorary Research Fellow
Department of Statistics
University of Auckland
Phone: +64-9-373-7599 ext. 88276



More information about the R-devel mailing list