[R] What if there's nothing to dispatch on?

Rolf Turner r@turner @end|ng |rom @uck|@nd@@c@nz
Thu Sep 2 12:21:30 CEST 2021


On Wed, 1 Sep 2021 19:29:32 -0400
Duncan Murdoch <murdoch.duncan using gmail.com> wrote:

<SNIP>

> I don't know the header of your foo() method, but let's suppose foo()
> is
> 
>    foo <- function(x, data, ...) {
>      UseMethod("foo")
>    }
> 
> with
> 
>    foo.formula <- function(x, data, ...) {
>      # do something with the formula x
>    }
> 
>    foo.default <- function(x, data, ...) {
>      # do the default thing.
>    }
> 
> Now you have
> 
>    xxx <- data.frame(u = 1:10, v = rnorm(10))
>    foo(x = u, y = v, data = xxx)
> 
> You want this to dispatch to the default method, because u is not a 
> formula, it's a column in xxx.  But how do you know that?  Maybe in
> some other part of your code you have
> 
>    u <- someresponse ~ somepredictor

Well I *don't* have such code anywhere, but a user could have such a
formula saved in the global environment.

> So now u *is* a formula, and this will dispatch to the formula
> method, causing havoc.
> 
> I think Bill's suggestion doesn't help here.  To do what you want to
> do doesn't really match what S3 is designed to do.

Yes.  I have come to realise that and have moved away from the S3
classes and method approach. I now have a solution with which I am
basically satisfied.  But I now understand the problem that you raised.
(Sorry to be so slow!  And thank you for the explanation.)

We need to guard against the possibility that a user may invoke the
"non-formula" syntax, foo(x,y,data)  where x is the predictor and y is
the response, and inadvertently trigger the formula syntax because
there is a pre-constructed formula, with the same name as x, hanging
about.

Not really very likely, but certainly not impossible.

I think that the following works:  suppose that x turns out (using
your handy-dandy try() trick) to be a formula.

    x1 <-try(x,silent=TRUE)

If inherits(x1,"formula") firstly check whether this formula exists in
the global environment:

    nmx <- deparse(substitute(x))
    if(exists(nmx,envir=.GlobalEnv)) {
        (throw an error)
    }

I have also added an argument forceFormula=FALSE, which if set to TRUE
prevents the error from being thrown.   Just in case using the formula
named by x *really is* what the user wants to do!

I've tested this out a bit (in my real application) and it seems to
work.  I'm sure that there are other pitfalls and Traps for Young
Players.  E.g. someone might call my function from inside
another function in which the offending formula is constructed.
So the offending formula *won't* be found in the global environment and
the error won't be triggered.  Psigh! Somebody will always be able to
find a way to break things. See fortunes::fortune(15).

However I think the code that I have written is reasonably robust, and
does what I want.  (BTW I want the function to accommodate the
"non-formula" syntax, as well as the formula syntax, to maintain some
semblance of backwards-compatibility.)

Thanks again for (a) the try() trick, and (b) pointing out the lurking
danger.

cheers,

Rolf

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



More information about the R-help mailing list