40

I'd like to push a function inside a package namespace so it can access internal objects of that package (let's use stats package as an example). I've tried using

myfun <- function(x) print(x)
env = loadNamespace("stats")
assign("myfun", myfun , env)

But it is locked. So I've tried to unlock my object

unlockBinding("myfun", env)

Since myfun doesn't exist yet, I can't unlock it.

Any help ?

bartektartanus
  • 15,284
  • 6
  • 74
  • 102
Etienne Racine
  • 1,323
  • 1
  • 11
  • 25

3 Answers3

42

Along the line of @Hadley's solution, but using the environment of the namespace, how about:

environment(myfun) <- asNamespace('stats')
Thomas
  • 43,637
  • 12
  • 109
  • 140
Mark Bravington
  • 526
  • 4
  • 2
  • in case that you need to modify an existing package function, which is to be called by other package functions, [here is the solution](https://stackoverflow.com/a/58238931/684229) – Tomas Oct 04 '19 at 15:10
  • How do you check whether this has worked successfully? – Sky Scraper Sep 29 '22 at 21:19
23

Why not just set the environment of your new function to the right place?

myfun <- function(x) print(x)
environment(myfun) <- as.environment("package:stats")
hadley
  • 102,019
  • 32
  • 183
  • 245
  • I didn't know that ! But I think I would like it to be namespace:stats instead of package:stats. Is there way to do that (just changing it in as.environment() doesn't work). – Etienne Racine Jun 23 '10 at 17:54
  • 7
    I'm late to the party, but this may be useful for others: The namespace actually is an environment. `namespace:stats` is a _descendent_ the global environment and contains all the objects. The exported objects get copied over to `package:stats`, which is an _ancestor_ of the global environment. – wch Aug 07 '12 at 00:04
7

You can access internal objects of a package using the triple colon operator :::. Take a look at, for example, as.roman and utils:::.roman2numeric. (Compare this to utils::.roman2numeric.) This could help you avoid having to put your function inside the namespace.

You might also want to look at dont.lockBindings in the mvbutils package, which stops namespaces being locked.

Richie Cotton
  • 118,240
  • 47
  • 247
  • 360
  • If I understand correctly, I cannot unlock a package's Namespace once it is locked (except by reloading it with dont.lockBindings). So it's impossible to add a new function a posteriori. – Etienne Racine Jun 22 '10 at 15:03
  • @Etiennebr: AFAIK you are correct. Once the namespace is locked, you can't add to it. I still think that `:::` is the way to proceed. – Richie Cotton Jun 22 '10 at 15:14