How do I override a non-visible function in the package namespace?
Asked Answered
B

1

33

I basically want to change a non-visible function of a package. For visible functions, i.e. functions that have no asterix when methods is called on them, I found two posts how I could achieve my goal:

  1. Use assignInNamespace: see post on R-help.
  2. Use fix: see post on stackoverflow

Although both approaches work for an exported / visible function (I use predict.lm as an example further below for the second approach and tested the first approach with the function subset.data.frame), they do not work for a non-visible function, e.g. predict.ar. Why is that? Is there a workaround?

Here is a minimal example:

Show that predict.lm is visible, predict.ar is not:

methods(predict)
 [1] predict.Arima*             predict.HoltWinters*       predict.StructTS*         
 [4] predict.ar*                predict.arima0*            predict.glm               
 [7] predict.lm                 predict.loess*             predict.mlm               
[10] predict.nls*               predict.poly               predict.ppr*              
[13] predict.prcomp*            predict.princomp*          predict.smooth.spline*    
[16] predict.smooth.spline.fit*

Apply predict.lm:

x <- rnorm(5)
y <- x + rnorm(5)
predict(lm(y ~ x))
#          1          2          3          4          5 
#  1.0783047  1.5288031  0.3268405  0.8373520 -0.9833746

Change predict.lm by entering cat("First line changed for predict.lm\n") at the beginning of the function body. (You have to do that manually in the editor):

fix(predict.lm)
predict(lm(y ~ x))
# First line changed for predict.lm
#          1          2          3          4          5 
#  1.0783047  1.5288031  0.3268405  0.8373520 -0.983374

Apply predict.ar:

sunspot.ar <- ar(sunspot.year)
predict(sunspot.ar, n.ahead=25)
# $pred
# Time Series:
# Start = 1989 
# End = 2013 

Try to change predict.ar:

fix(predict.ar) #Here, an empty function body appears for me
fix("stats:::predict.ar") #Here as well
fix(stats:::predict.ar)
#Error in fix(stats:::predict.ar) : 'fix' requires a name

Try to use assignInNamespace instead. (Note that I just copied the function stats:::predict.ar in an editor and added the line cat("First line changed for predict.ar\n") at the beginning of the body. Because the function body is quite long, I only show the first couple of lines here)

mypredict <- function (object, newdata, n.ahead = 1, se.fit = TRUE, ...) 
{
    cat("First line changed for predict.ar\n")
    if (n.ahead < 1) 
        stop("'n.ahead' must be at least 1")
    #Rest of body of stats:::predict.ar
}
assignInNamespace("predict.ar", mypredict, ns="stats")
predict(sunspot.ar, n.ahead=25)
# First line changed for predict.ar
# Error in predict.ar(sunspot.ar, n.ahead = 25) : 
#   object 'C_artoma' not found

Since "First line changed for predict.ar" is actually printed to the console, predict.ar must have been changed. However, why is the object 'C_artoma' not found anymore?

UPDATE: OK, this is super embarrassing, but I can't delete that post anymore: The answer was already at the link I provided with Richie Cotton's answer at the end. Sorry for wasting your time! I think I checked everything and then I don't see the obvious. Could someone just post this as an answer an I accept it. Sorry again.

fixInNamespace(predict.ar, pos="package:stats")
Bilow answered 5/1, 2012 at 13:33 Comment(1)
Hey is this change permanent? When I start R again and load the package the change will persist? And is there a way to this for an R6 Class, I am looking for a way to modify an R6 class defined inside a package.Attaboy
B
26

Use fixInNamespace. :)

fixInNamespace("predict.ar", "stats")

or

fixInNamespace("predict.ar", pos="package:stats")

(Several years later...)
From Nicholas H's comment: if you want to push some code to CRAN that depends upon an internal function from another package, it will throw a build warning and be rejected by R-core. If you want that internal function, you should just take a copy of it using the ::: operator and maintain it yourself.

predict.ar <- stats:::predict.ar
Brett answered 5/1, 2012 at 13:33 Comment(8)
OK, I'm quite mad at myself for not checking every link accurately again before posting (stackoverflow really needs a preview option and the option to downvote yourself...), but that you are actually the one giving the correct answer just made my day. So thanks for that!Bilow
@Bilow I'm providing a down-voting service for a fee. If you're interested... :)Asarum
@RomanLuštrik Haha, good one. I'm gonna think about it and let you know soonish if I'm interested ;-)Bilow
Well, I'm not voting to close since this taught me something, and yet again @Richie Cotton knows more R than I.Killick
How can I use these types of functions in a package, to submit to CRAN?Fritts
@NicholasHamilton Why?Powerful
@Dason, My initial question is quite old. I published a package (www.ggtern.com) which needed to patch some ggplot2 functions in order to allow for the extra dimension, and, many new theme elements. My package is effectively an "extension" to ggplot2, for a very specific case, namely the plotting of ternary diagrams. To cut a long story short, assignInNamespace(...) CANNOT be used in any way whatsoever. Here is some additional info on what I ended up doing: groups.google.com/forum/#!topic/ggplot2/SZX-SF9UCRoFritts
For some reason, this did not seem to work in the context of a markdown document. assignInNamespace() did, although I did have to link all the hidden functions (in my new version of the function that I wanted replaced) using the environment:::function() notation, and that worked.Letreece

© 2022 - 2024 — McMap. All rights reserved.