Skip to content

Getting hold of a package's environment from C code

11 messages · Duncan Murdoch, Deepayan Sarkar, Seth Falcon +2 more

#
Hi,

I have a package where I'm calling an R function (say "foo") from C
code. "foo" is in the same package, but is not exported. I construct
the call using lang1(install("foo")), but to eval it I need the
package's environment.  Is there a way to do this? Passing the correct
environment through .Call() is not an option.

Right now, I'm getting the environment first using something like

  rho = PROTECT(eval(lang2(install("environment"), install("bar")),
R_GlobalEnv))

where bar _is_ exported. However, this doesn't work if the package is
loaded but not attached, and is also risky because someone might
define another "bar" that is found first.

One solution that might work is to make 'rho' a global variable and
assign the correct value when the package is loaded. Is that a good
idea? How should I PROTECT it?

-Deepayan
#
On 10/22/2006 3:56 PM, Deepayan Sarkar wrote:
In R code, you could use getNamespace("pkg") to get the namespace 
environment.  I haven't tried this, but I'd assume

PROTECT(rho = eval(lang2(install("getNamespace"),
                          ScalarString(mkChar("pkg"))));

(or something like it) would be the C equivalent.

 >
 > One solution that might work is to make 'rho' a global variable and
 > assign the correct value when the package is loaded. Is that a good
 > idea? How should I PROTECT it?

I'd say to avoid globals if you can, and I think you can here.

Duncan Murdoch
#
On 10/22/06, Duncan Murdoch <murdoch at stats.uwo.ca> wrote:
Thanks, that works perfectly.

-Deepayan
#
"Deepayan Sarkar" <deepayan.sarkar at gmail.com> writes:
Perhaps:

R_FindNamespace(mkString(where))


+ seth
#
Seth Falcon <sfalcon at fhcrc.org> writes:
Sorry, this won't help you for package-level code as this function is
part of the internal use only API.  It would be nice to have access to
it or a similar function from C in package code.
#
On Sun, 22 Oct 2006, Deepayan Sarkar wrote:

            
mkString("pkg") is simpler than ScalarString(mkChar("pkg")).
#
On Sun, 22 Oct 2006, Seth Falcon wrote:

            
Hmm, it is declared in Rinternals.h, which is the public header for 
manipulating R objects at C level.  As such it is available to packages, 
but as it is not documented in 'Writing R Extensions' it is subject to 
change.

R_FindNamespace is essentially the same code as Duncan M provided, so it 
is a pretty simple function.  (It still contains a test that namespaces 
are supported, and that seems long overdue for removal.)
#
As far as I can tell from the original post, Deepayan asked for a way 
to find a package's namespace environment (rather than the package 
environment, <namespace:foo> not <package:foo>), so the subject line is 
subject to misinterpretation.
On Mon, 23 Oct 2006, Prof Brian Ripley wrote:

            
I think Deepayan's original enquiry was about getting hold of a namespace 
environment from within an already loaded namespace.  That can be done 
entirely at C level, as we don't have the complication of possibly loading 
the namespace.  Just

     val = findVarInFrame(R_NamespaceRegistry, install("pkgname"));

does that job, with val == R_UnboundValue should the namespace not be 
loaded.  AFAICS, everything here is available to a package writer, and 
this is equally undocumented.
#
On Mon, 23 Oct 2006, Prof Brian Ripley wrote:

            
Except for a small detail: the code in R_FindNamespace protects the
expression before callign eval -- this is needed since eval does not.

Best,

luke
#
On Mon, 23 Oct 2006, Prof Brian Ripley wrote:

            
This level of detail should remain undocumented as it might be useful
to change the representation at some point. R_FindNamespace is a safer
bet, and we probably should document it as officially available..

Best,

luke
#
On 10/23/06, Luke Tierney <luke at stat.uiowa.edu> wrote:
OK, so I'm now using

   rho = PROTECT(R_FindNamespace(mkString("mypkg"))),

Thanks,
Deepayan