modifying data in a package

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

modifying data in a package

Ross Boylan
I've tweaked Rmpi and want to have some variables that hold data in the
package.  One of the R files starts
mpi.isend.obj <- vector("list", 500) #mpi.request.maxsize())                                                                          
mpi.isend.inuse <- rep(FALSE, 500) #mpi.request.maxsize())    

and then functions update those variables with <<-.  When run:
  Error in mpi.isend.obj[[i]] <<- .force.type(x, type) :                                                                                
  cannot change value of locked binding for 'mpi.isend.obj'

I'm writing to ask the proper way to accomplish this objective (getting
a variable I can update in package namespace--or at least somewhere
useful and hidden from the outside).

I think the problem is that the package namespace is locked.  So how do
I achieve the same effect?
http://www.r-bloggers.com/package-wide-variablescache-in-r-packages/
recommends creating an environment and then updating it.  Is that the
preferred route?  (It seems odd that the list should be locked but the
environment would be manipulable.  I know environments are special.)

The comments indicate that 500 "should" be mpi.request.maxsize().  That
doesn't work because mpi.request.maxsize calls a C function, and there
is an error that the function isn't loaded.  I guess the R code is
evaluated before the C libraries are loaded. The packages zzz.R starts
.onLoad <- function (lib, pkg) {
    library.dynam("Rmpi", pkg, lib)

So would moving the code into .onLoad after that work?  In that case,
how do I get the environment into the  proper scope?  Would
 .onLoad <- function (lib, pkg) {
    library.dynam("Rmpi", pkg, lib)
    assign("mpi.globals", new.env(), environment(mpi.isend))
    assign("mpi.isend.obj", vector("list", mpi.request.maxsize(),
mpi.globals)
work?

mpi.isend is a function in Rmpi.  But I'd guess the first assign will
fail because the environment is locked.

Thanks.
Ross Boylan

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: modifying data in a package [a solution]

Ross Boylan
On Wed, 2014-03-19 at 19:22 -0700, Ross Boylan wrote:

> I've tweaked Rmpi and want to have some variables that hold data in the
> package.  One of the R files starts
> mpi.isend.obj <- vector("list", 500) #mpi.request.maxsize())                                                                          
> mpi.isend.inuse <- rep(FALSE, 500) #mpi.request.maxsize())    
>
> and then functions update those variables with <<-.  When run:
>   Error in mpi.isend.obj[[i]] <<- .force.type(x, type) :                                                                                
>   cannot change value of locked binding for 'mpi.isend.obj'
>
> I'm writing to ask the proper way to accomplish this objective (getting
> a variable I can update in package namespace--or at least somewhere
> useful and hidden from the outside).
>
I've discovered one way to do it:
In one of the regular R files
mpi.global <- new.env()

Then at the end of .onLoad in zzz.R:
assign("mpi.isend.obj", vector("list", mpi.request.maxsize()),
mpi.global)
and similary for the logical vector mpi.isend.inuse

Access with functions like this:
## Next 2 functions have 3 modes                                                                                                      
##  foo()  returns foo from mpi.global                                                                                                
##  foo(request) returns foo[request] from mpi.global                                                                                
##  foo(request, value) set foo[request] to value                                                                                    
mpi.isend.inuse <- function(request, value) {
    if (missing(request))
        return(get("mpi.isend.inuse", mpi.global))
    i <- request+1L
    parent.env(mpi.global) <- environment()
    if (missing(value))
        return(evalq(mpi.isend.inuse[i], mpi.global))
    return(evalq(mpi.isend.inuse[i] <- value, mpi.global))
}

# request, if present, must be a single value                                                                                        
mpi.isend.obj <- function(request, value){
    if (missing(request))
        return(get("mpi.isend.obj", mpi.global))
    i <- request+1L
    parent.env(mpi.global) <- environment()
    if (missing(value))
        return(evalq(mpi.isend.obj[[i]], mpi.global))
    return(evalq(mpi.isend.inuse[[i]] <- value, mpi.global))
}

This is pretty awkward; I'd love to know a better way.  Some of the
names probably should change too: mpi.isend.obj() sounds too much as if
it actually sends something, like mpi.isend.Robj().

Ross

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel