Search
Question: custom iterators and foreach inside package - fails
0
gravatar for ben.ward
22 months ago by
ben.ward30
United Kingdom
ben.ward30 wrote:

Hi, hopefully someone out there is good with foreach and iterators! I've been struggling with this:

 

I have created a custom iterator, inheriting from there iter class in the iterators package. The iterator and its methods are not exported from the package. Here is the iterator and a test function in a script that is reproducible and runnable, the iterator is called pairsRef:

library(Biostrings)
library(iterators)
library(foreach)    

setGeneric("maskSequences", function(object, seqnames, invert = TRUE, append = "union"){
  standardGeneric("maskSequences")
})

setMethod("maskSequences",
          signature("DNAMultipleAlignment", "character", "logical", "character"),
          function(object, seqnames, invert, append) {
            sequenceNames <- rownames(object)
            rowmask(object, append = append, invert = invert) <-
              which(sequenceNames %in% seqnames)
            return(object)
          })

pairsRef <- function(obj, ...){
  UseMethod('pairsRef')
}

pairsRef.DNAMultipleAlignment <-
  function(obj, ref = NULL, checkFun = function(x, ...) TRUE){
    state <- new.env()
    state$i <- 0L
    state$obj <- obj
    if(is.null(ref)){
      state$ref <- rownames(obj)[1]
    } else {
      state$ref <- ref
    }
    state$nonRefs <- rownames(obj)
    state$nonRefs <- state$nonRefs[state$nonRefs != state$ref]
    it <- list(state=state, checkFun = checkFun)
    class(it) <- c("pairsRef", "abstractiter", "iter")
    return(it)
  }

nextElem.pairsRef <- function(obj, ...){
  repeat {
    obj$state$i <- obj$state$i + 1L
    if(obj$state$i > length(obj$state$nonRefs))
      stop('StopIteration', call.=FALSE)
    pair <- maskSequences(obj$state$obj,
                          c(obj$state$ref, obj$state$nonRefs[obj$state$i]),
                          invert = TRUE,
                          append = "replace"
    )
    if(obj$checkFun(pair)){
      return(pair)
    }
  }
}

Test2 <- function(dna, ref){
  pit <- pairsRef(dna, ref = ref, checkFun = function(x) TRUE)
  results <- foreach(x = pit, .combine = c, .multicombine = TRUE) %do% {x}
  return(results)
}

dna <-
  readDNAMultipleAlignment(filepath =
                             system.file("extdata",
                                         "msx2_mRNA.aln",
                                         package="Biostrings"),
                           format="clustal")

Test2(dna, rownames(dna)[1])

 

However, I want to use this iterator to do foreach loops in a package of mine. If I put Test2 in a package (exported), and I have all the other functions in the package (unexported), and I have the package namespace import Biostrings, iterators, and foreach. It does not work. With a fresh R session, loading the package, and the running:

 

dna <-
  Biostrings::readDNAMultipleAlignment(filepath =
                             system.file("extdata",
                                         "msx2_mRNA.aln",
                                         package="Biostrings"),
                           format="clustal")

Test2(dna, rownames(dna)[1])

 

Is this because the custom iterator is internal to the package? Any help or suggestions are greatly appreciated.

 

If I export the iterator and it's functions from the package. Then all works fine. But I don't necessarily want to export iterators of the package.

 

I have tried to look at the code for `%do%` in foreach, and have found `doSEQ` has.... environmenty stuff ... it gets called with parent.frame() and such on.

Has anyone else used custom iterators and foreach in their packages? How did you do it?

Many thanks,

Ben.

ADD COMMENTlink modified 22 months ago • written 22 months ago by ben.ward30
1
gravatar for ben.ward
22 months ago by
ben.ward30
United Kingdom
ben.ward30 wrote:

I've managed to solve this.

In order for foreach to work inside the package with non-exported iterators, the method nextElem must be imported from iterators, and then the additional method unique to the package, exported, such that it is visible to the functions in the foreach package namespace.

ADD COMMENTlink written 22 months ago by ben.ward30

A test for your solution would be to ensure that the package works when it is loaded but not attached, for instance if the iterator were use in  a function foo() then invoke foo without it being on the search path, in a new R session yourpkg::foo() without first saying library(foo). This is how a package that Imports: your package would see foo().

ADD REPLYlink written 22 months ago by Martin Morgan ♦♦ 20k
Please log in to add an answer.

Help
Access

Use of this site constitutes acceptance of our User Agreement and Privacy Policy.
Powered by Biostar version 2.2.0
Traffic: 129 users visited in the last hour