[R] Hashes as S4 Classes, or: How to separate environments
For learning purposes mainly I attempted to implement hashes/maps/dictionaries (Python lingua) as S4 classes, see the coding below. I came across some rough S4 edges, but in the end it worked (for one dictionary). When testing ones sees that the dictionaries D1 and D2 share their environments [EMAIL PROTECTED] and [EMAIL PROTECTED], though I thought a new and empty environment would be generated each time 'new(Dict)' is called. QUESTION: How can I separate the environments [EMAIL PROTECTED] and [EMAIL PROTECTED] ? Reading the articles mentioned in Tipps and Tricks didn't help me really. Of course, I will welcome other corrections and improvements as well. Working in R 2.7.0 under Windows. Hans Werner #-- Class and method definition for dictionaries --- setClass(Dict, representation (hash = environment), prototype (hash = new.env(hash=T, parent = emptyenv())) ) setMethod(show, signature(object=Dict), definition = function(object) ls([EMAIL PROTECTED]) ) setGeneric(hclear, function(object) standardGeneric(hclear)) setMethod(hclear, signature(object=Dict), function(object) rm(list=ls([EMAIL PROTECTED]), [EMAIL PROTECTED]) ) setGeneric(hput, function(object, key, value) standardGeneric(hput)) setMethod(hput, signature(object=Dict, key=character, value=ANY), function(object, key, value) assign(key, value, [EMAIL PROTECTED]) ) setGeneric(hget, function(object, key, ...) standardGeneric(hget)) setMethod(hget, signature(object=Dict, key=character), function(object, key) { if (exists(key, [EMAIL PROTECTED], inherits = FALSE)) { get(key, [EMAIL PROTECTED]) } else { return(NULL) } } ) # Some tests D1 - new(Dict) hput(D1, a, 1) # Same as: [EMAIL PROTECTED] - 1 hput(D1, b, 2) hget(D1, a) hget(D1, b) show(D1) D2 - new(Dict) hput(D2, c, 3) hput(D2, d, 4) hget(D2, a) # Wrong: was defined only for D1 hget(D2, b) show(D2) hclear(D2) # Wrong: clears D1 too show(D1) #- __ R-help@r-project.org mailing list 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.
Re: [R] Hashes as S4 Classes, or: How to separate environments
Hi Hans -- Hans W Borchers [EMAIL PROTECTED] writes: For learning purposes mainly I attempted to implement hashes/maps/dictionaries (Python lingua) as S4 classes, see the coding below. I came across some rough S4 edges, but in the end it worked (for one dictionary). When testing ones sees that the dictionaries D1 and D2 share their environments [EMAIL PROTECTED] and [EMAIL PROTECTED], though I thought a new and empty environment would be generated each time 'new(Dict)' is called. QUESTION: How can I separate the environments [EMAIL PROTECTED] and [EMAIL PROTECTED] ? The prototype is created once, at class creation time. So all objects derived from the prototype share the same environment (other types like 'list' would have the illusion of being created anew, because of copy-on-change semantics). A solution is to have an initialize method that recreates the hash each time. setMethod(initialize, signature=signature(.Object=Dict), function(.Object, hash=new.env(hash=TRUE, parent=emptyenv()), ...) { callNextMethod(.Object, hash=hash, ...) }) Another solution is to have a constructor that feeds Dict a new environment Dict - function() { new(Dict, hash=new.env(hash=TRUE, parent=emptyenv()) } The latter is perhaps preferable, both from an aesthetic / user point of view ('Dict()' better than 'new(Dict)') and from the nuances-of-S4 point of view (e.g., the default 'initialize' method is documented, though not in so many words, as a copy constructor, taking slots in it's first argument as defaults; 'initialize' above does not satisfy that contract). I know others have implemented Dict objects; it would be fun to hear from them. Martin Reading the articles mentioned in Tipps and Tricks didn't help me really. Of course, I will welcome other corrections and improvements as well. Working in R 2.7.0 under Windows. Hans Werner #-- Class and method definition for dictionaries --- setClass(Dict, representation (hash = environment), prototype (hash = new.env(hash=T, parent = emptyenv())) ) setMethod(show, signature(object=Dict), definition = function(object) ls([EMAIL PROTECTED]) ) setGeneric(hclear, function(object) standardGeneric(hclear)) setMethod(hclear, signature(object=Dict), function(object) rm(list=ls([EMAIL PROTECTED]), [EMAIL PROTECTED]) ) setGeneric(hput, function(object, key, value) standardGeneric(hput)) setMethod(hput, signature(object=Dict, key=character, value=ANY), function(object, key, value) assign(key, value, [EMAIL PROTECTED]) ) setGeneric(hget, function(object, key, ...) standardGeneric(hget)) setMethod(hget, signature(object=Dict, key=character), function(object, key) { if (exists(key, [EMAIL PROTECTED], inherits = FALSE)) { get(key, [EMAIL PROTECTED]) } else { return(NULL) } } ) # Some tests D1 - new(Dict) hput(D1, a, 1) # Same as: [EMAIL PROTECTED] - 1 hput(D1, b, 2) hget(D1, a) hget(D1, b) show(D1) D2 - new(Dict) hput(D2, c, 3) hput(D2, d, 4) hget(D2, a) # Wrong: was defined only for D1 hget(D2, b) show(D2) hclear(D2) # Wrong: clears D1 too show(D1) #- __ R-help@r-project.org mailing list 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. -- Martin Morgan Computational Biology / Fred Hutchinson Cancer Research Center 1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109 Location: Arnold Building M2 B169 Phone: (206) 667-2793 __ R-help@r-project.org mailing list 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.
Re: [R] Hashes as S4 Classes, or: How to separate environments
On May 10, 2008, at 7:30 AM, Hans W Borchers wrote: For learning purposes mainly I attempted to implement hashes/maps/ dictionaries (Python lingua) as S4 classes, see the coding below. I came across some rough S4 edges, but in the end it worked (for one dictionary). When testing ones sees that the dictionaries D1 and D2 share their environments [EMAIL PROTECTED] and [EMAIL PROTECTED], though I thought a new and empty environment would be generated each time 'new(Dict)' is called. QUESTION: How can I separate the environments [EMAIL PROTECTED] and [EMAIL PROTECTED] ? The problem you are encountering is that the prototype is only created once. Because environments are passed by reference, [EMAIL PROTECTED] and [EMAIL PROTECTED] are the exact same environment: D1 - new(Dict) D1 [EMAIL PROTECTED] environment: 0x182ac870 D2 - new(Dict) [EMAIL PROTECTED] environment: 0x182ac870 You have assumed that setClass will be executed for each new dictionary, or at least that the prototype(...) part of it would run each time. Not wanting right now to dig into the internals of setClass, my guess is that it only creates a prototype once, and then just reuses it each time, with something like an assignment operator. One solution, very similar to what Martin just suggested, is below. I believe another solution might be to have the hash be a list containing an environment, though I haven't tried that. The solution is to create a constructor function, the function newDict below: setClass(Dict, representation (hash = environment)) ) newDict - function() { obj - new(Dict) [EMAIL PROTECTED] - new.env(hash=T, parent = emptyenv()) obj } In practice, you would probably want newDict to accept an arguments, which may be a list or another Dict object, and then use that as a starting point for the new hash. Here's a sample run: # Some tests D1 - newHash() D2 - newHash() [EMAIL PROTECTED] environment: 0x1e80c98 [EMAIL PROTECTED]# Notice the different address environment: 0x1e868fc hput(D1, a, 1) hget(D1, a) [1] 1 show(D1) [1] a hput(D2, c, 3) hget(D2, a) # Does the correct thing this time NULL hget(D2, c) [1] 3 show(D2) [1] c hclear(D2) show(D1)# Works properly now [1] a #- Haris Skiadas Department of Mathematics and Computer Science Hanover College Reading the articles mentioned in Tipps and Tricks didn't help me really. Of course, I will welcome other corrections and improvements as well. Working in R 2.7.0 under Windows. Hans Werner #-- Class and method definition for dictionaries --- setClass(Dict, representation (hash = environment), prototype (hash = new.env(hash=T, parent = emptyenv())) ) setMethod(show, signature(object=Dict), definition = function(object) ls([EMAIL PROTECTED]) ) setGeneric(hclear, function(object) standardGeneric(hclear)) setMethod(hclear, signature(object=Dict), function(object) rm(list=ls([EMAIL PROTECTED]), [EMAIL PROTECTED]) ) setGeneric(hput, function(object, key, value) standardGeneric (hput)) setMethod(hput, signature(object=Dict, key=character, value=ANY), function(object, key, value) assign(key, value, [EMAIL PROTECTED]) ) setGeneric(hget, function(object, key, ...) standardGeneric(hget)) setMethod(hget, signature(object=Dict, key=character), function(object, key) { if (exists(key, [EMAIL PROTECTED], inherits = FALSE)) { get(key, [EMAIL PROTECTED]) } else { return(NULL) } } ) # Some tests D1 - new(Dict) hput(D1, a, 1) # Same as: [EMAIL PROTECTED] - 1 hput(D1, b, 2) hget(D1, a) hget(D1, b) show(D1) D2 - new(Dict) hput(D2, c, 3) hput(D2, d, 4) hget(D2, a) # Wrong: was defined only for D1 hget(D2, b) show(D2) hclear(D2) # Wrong: clears D1 too show(D1) #- __ R-help@r-project.org mailing list 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.