[Rd] specials and ::

Duncan Murdoch murdoch@dunc@n @end|ng |rom gm@||@com
Mon Aug 26 18:58:06 CEST 2024


On 2024-08-26 12:34 p.m., Duncan Murdoch wrote:
> On 2024-08-26 10:42 a.m., Therneau, Terry M., Ph.D. via R-devel wrote:
>> The survival package makes significant use of the "specials" argument of terms(), before
>> calling model.frame; it is part of nearly every modeling function. The reason is that
>> strata argments simply have to be handled differently than other things on the right hand
>> side. Likewise for tt() and cluster(), though those are much less frequent.
>>
>> I now get "bug reports" from the growing segment that believes one should put
>> packagename:: in front of every single instance.   For instance
>>          fit <- survival::survdiff( survival::Surv(time, status) ~ ph.karno +
>> survival::strata(inst),  data= survival::lung)
>>
>> This fails to give the correct answer because it fools terms(formula, specials=
>> "strata").    I've stood firm in my response of "that's your bug, not mine", but I begin
>> to believe I am swimming uphill.   One person responded that it was company policy to
>> qualify everything.
>>
>> I don't see an easy way to fix survival, and even if I did it would be a tremendous amout
>> of work.   What are other's thoughts?
> 
> I received a similar complaint about the tables package, which had
> assumed during argument processing that it was on the search list in
> order to find a function (see
> https://github.com/dmurdoch/tables/issues/30 if you want the details).
> In my case there's only one function exported by tables that wasn't
> being found, "labelSubset".
> 
> I don't know any of the details of the survival problems.  When I try
> your example code above without attaching survival, it appears to work.
> So my solution might be irrelevant to you.
> 
> The way I found to work around this was to use this code early in the
> processing, when it is trying to turn the data argument into an environment:
> 
>       parent <- if (is.environment(data)) data else environment(table)
>       if (!exists("labelSubset", envir = parent)) {
>         withTableFns <- new.env(parent = parent)
>         withTableFns$labelSubset <- labelSubset
>       } else
>         withTableFns <- parent
> 
>       if (is.null(data))
>       	data <- withTableFns
>       else if (is.list(data))
>       	data <- list2env(data, parent = withTableFns)
>       else if (!is.environment(data))
>       	stop("'data' must be a dataframe, list or environment")

Of course, posting this meant I discovered a bug in it:  if 
is.environment(data) was TRUE, the modification was ignored.  Line 8 
should be

        if (is.null(data) || is.environment(data))

to handle that case.

Duncan Murdoch

>       	
> This inserts a new environment containing just that one tables function.
> 
> One issue is if a user has "labelSubset" already in the environment; I
> decided to use that one on the assumption that the user did it
> intentionally.  It would have been better to use a name that was less
> likely to show up in another package, but it's old code.
> 
> This isn't on CRAN yet, so I'd be interested in hearing about problems
> with this approach, or better solutions.
> 
> Duncan Murdoch



More information about the R-devel mailing list