Ivan Krylov
2018-Aug-27 16:25 UTC
[R] "use of NULL environment is defunct" when trying to lock a reference class
Hi! I'm trying to create a persistent memoising class with a destructor and an option to evaluate cache misses in parallel. I want to lock all its fields because it doesn't make sense to change them after the filename, the environment object and the function are set in the object. (I'm not sure whether I should lock the environment field I use as the hash, though.) The problem is, I can't figure out how to use class$lock(...) properly:> test.class <- setRefClass("test", fields=c("field")) > test.class$lock("field")Error in .makeDefaultBinding(current at field, current at className, TRUE, environment(current)) : use of NULL environment is defunct By looking at traceback() and source of methods:::.lockRefFields, I see that environment(zzz at generator$def at fieldPrototypes[["field"]]) is, indeed, NULL. I'm using R version 3.3.3 (2017-03-06), version$`svn rev` is "72310". What am I doing wring? -- Best regards, Ivan P.S. Please Cc me in your replies to the list, if possible.
Eric Berger
2018-Aug-27 18:48 UTC
[R] "use of NULL environment is defunct" when trying to lock a reference class
Hi Ivan, Unfortunately I cannot answer your question. However, I do have quite a bit of experience using R's reference classes and you might want to consider the more recent R6 package. It provides R6 classes which have advantages over reference classes. See for example: 1. Hadley Wickham on R6 (chapter 16 in "Advanced R") https://adv-r.hadley.nz/r6.html 2. The R6 package documentation which seems to mention 'lock' in quite a few places https://cran.r-project.org/web/packages/R6/R6.pdf HTH, Eric On Mon, Aug 27, 2018 at 7:25 PM, Ivan Krylov <krylov.r00t at gmail.com> wrote:> Hi! > > I'm trying to create a persistent memoising class with a destructor and > an option to evaluate cache misses in parallel. I want to lock all > its fields because it doesn't make sense to change them after the > filename, the environment object and the function are set in the > object. (I'm not sure whether I should lock the environment field I use > as the hash, though.) > > The problem is, I can't figure out how to use class$lock(...) properly: > > > test.class <- setRefClass("test", fields=c("field")) > > test.class$lock("field") > Error in .makeDefaultBinding(current at field, current at className, TRUE, > environment(current)) : > use of NULL environment is defunct > > By looking at traceback() and source of methods:::.lockRefFields, > I see that environment(zzz at generator$def at fieldPrototypes[["field"]]) > is, indeed, NULL. > > I'm using R version 3.3.3 (2017-03-06), version$`svn rev` is "72310". > > What am I doing wring? > > -- > Best regards, > Ivan > > P.S. Please Cc me in your replies to the list, if possible. > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/ > posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >[[alternative HTML version deleted]]
Ivan Krylov
2018-Aug-28 20:49 UTC
[R] "use of NULL environment is defunct" when trying to lock a reference class
Hi Eric, Thank you for your answer! On Mon, 27 Aug 2018 21:48:50 +0300 Eric Berger <ericjberger at gmail.com> wrote:> you might want to consider the more recent R6 packageIndeed, R6 has private fields which fits my idea of an object with mutable state even better. My original problem seems to be solved and I'm posting my code (CC0) in case someone else needs it as a reference: require(digest); require(R6) memoised <- R6Class( "memoised", lock_objects=T, lock_class=T, cloneable=F, private=list(fun=NULL, storage=NULL, cache=NULL), public=list( initialize=function(fun, storage) { # constructor private$fun <- fun private$storage <- storage private$cache <- tryCatch( { load(storage) cache }, error = function(e) { new.env(T, emptyenv()) } ) }, eval=function(...) { # behave as cached fun hash <- digest(list(...), algo="sha1") if (exists(hash, private$cache)) return(get(hash, private$cache)) val <- private$fun(...) assign(hash, val, private$cache) val }, par.eval=function(args, cl) { # args is list of argument lists # hash all because we'll need them later hashes <- lapply(args, digest, algo="sha1") # indices of not yet evaluated in the original args array missing <- Filter(function(i) !exists(hashes[[i]], private$cache), seq_along(args)) # evaluate and save them values <- parLapply(cl, args[missing], function(l) do.call(private$fun,l)) private$cache[hashes[missing]] <- values # get all requested hashes private$cache[hashes] }, finalize=function() { # destructor cache <- private$cache # must have known name for restore save(cache, file=private$storage) } ) ) It's still a mystery why did setRefClass refuse to lock my class, but at least it's not blocking my progress. -- Best regards, Ivan