Peter Ruckdeschel
2003-Nov-19 18:51 UTC
[Rd] Was: setValidity and "initialize" method conflict ? [in R-help]
Hello, Thomas Stabla (statho3@web.de) has already sent this question to R-help, Wed, 12 Nov 2003 21:21:31 +0100, but we are not sure whether we should better post this mail to this audience than to R-help: --------------------------------------------------------------------- We are using S4-classes and want to force a validity check when an object is created. How can this be done, when an "initalize" method has been set? ------------------------------------------------------------------------- We got problems when using our own "initalize" method: platform i686-pc-linux-gnu arch i686 os linux-gnu system i686, linux-gnu status major 1 minor 7.1 year 2003 month 06 day 16 language R [But the same behaviour ouccured under R 1.8.0] Following piece of code works fine, just like we expected it to ------------------------------------------------------------------------- >setClass("Foo", representation(woo = "numeric")) [1] "Foo" >validFooObject <- function(object) { + if(object@woo > 0) return(TRUE) + else return("warning: negative value for woo")} >setValidity("Foo", validFooObject) [1] "Foo" >new("Foo", woo = 1) # all is fine An object of class "Foo" Slot "woo": [1] 1 >new("Foo", woo = -1) # ok, negative value Error in validObject(.Object) : Invalid "Foo" object: warning: negative value for woo ------------------------------------------------------------------------- Now, if i define a initialize method for Foo, things change (R had been restarted) ------------------------------------------------------------------------- >setClass("Foo", representation(woo = "numeric")) [1] "Foo" >validFooObject <- function(object) { + if(object@woo > 0) return(TRUE) + else return("warning: negative value for woo")} >setValidity("Foo", validFooObject) [1] "Foo" >setMethod("initialize", "Foo", function(.Object, woo){ + .Object@woo = woo + .Object}) [1] "initialize" >new("Foo", woo = 1) # all is fine An object of class "Foo" Slot "woo": [1] 1 >new("Foo", woo = -1) # ! no warning, object created! An object of class "Foo" Slot "woo": [1] -1 ------------------------------------------------------------------------- Thank you for your attention. -- Peter Ruckdeschel
John Chambers
2003-Nov-20 15:53 UTC
[Rd] Was: setValidity and "initialize" method conflict ? [in R-help]
Peter Ruckdeschel wrote:> > Hello, > > Thomas Stabla (statho3@web.de) has already sent this > question to R-help, Wed, 12 Nov 2003 21:21:31 +0100, > but we are not sure whether we should better post this > mail to this audience than to R-help: > > --------------------------------------------------------------------- > > We are using S4-classes and want to force a validity check > when an object is created. > > How can this be done, when an "initalize" method has been > set?The basic point is that the call to validObject() occurs in the default method for initialize(), and only when some arguments have been included in the call to new() in addition to the class name. (Do getMethod("initialize") to see the definition.) When you override the default method, you have a choice of whether to call validObject() or not (you might not want to if you're fussy about efficiency). If you do want to validate the object, there are two ways to do so: 1- Use callNextMethod to call the default method as part of your method (this is often a good idea anyway). 2- call validObject directly after initializing the object. Here's an example, run against the current 1.8.1 patched. R> validC1 <- function(object) { if (all(object@x > 0)) TRUE else "Negative values not allowed in x slot" } R> setClass("C1", representation(x = "numeric"), validity = validC1) [1] "C1" R> setClass("C2", representation(id = "character"), contains = "C1") [1] "C2" By the way, in the validity method you should not return a call to warning() as in your example. The validity method just returns a character string describing the problem. To define an initialize method for C2 in the first way, do something like: R> setMethod("initialize", "C2", function(.Object, x, id) { callNextMethod(.Object, x = x) .Object@id <- id .Object }) [1] "initialize" Then: R> new("C2", x = 1, id = "OK") An object of class "C2" Slot "id": [1] "OK" Slot "x": numeric(0) R> try(new("C2", x = -1, id = "BAD!")) Error in validObject(.Object) : Invalid "C2" object: Negative values not allowed in x slot The same effect is obtained in the second way by something like: R> setMethod("initialize", "C2", function(.Object, x, id) { .Object@x <- x .Object@id <- id validObject(.Object) .Object }) John Chambers> > ------------------------------------------------------------------------- > We got problems when using our own "initalize" method: > > platform i686-pc-linux-gnu > arch i686 > os linux-gnu > system i686, linux-gnu > status > major 1 > minor 7.1 > year 2003 > month 06 > day 16 > language R > > [But the same behaviour ouccured under R 1.8.0] > > Following piece of code works fine, just like we expected it to > > ------------------------------------------------------------------------- > >setClass("Foo", representation(woo = "numeric")) > [1] "Foo" > >validFooObject <- function(object) { > + if(object@woo > 0) return(TRUE) > + else return("warning: negative value for woo")} > > >setValidity("Foo", validFooObject) > [1] "Foo" > > >new("Foo", woo = 1) # all is fine > An object of class "Foo" > Slot "woo": > [1] 1 > > >new("Foo", woo = -1) # ok, negative value > Error in validObject(.Object) : Invalid "Foo" object: warning: negative > value for woo > > ------------------------------------------------------------------------- > > Now, if i define a initialize method for Foo, things change (R had > been restarted) > > ------------------------------------------------------------------------- > >setClass("Foo", representation(woo = "numeric")) > [1] "Foo" > > >validFooObject <- function(object) { > + if(object@woo > 0) return(TRUE) > + else return("warning: negative value for woo")} > > >setValidity("Foo", validFooObject) > [1] "Foo" > > >setMethod("initialize", "Foo", function(.Object, woo){ > + .Object@woo = woo > + .Object}) > [1] "initialize" > > >new("Foo", woo = 1) # all is fine > An object of class "Foo" > Slot "woo": > [1] 1 > > >new("Foo", woo = -1) # ! no warning, object created! > An object of class "Foo" > Slot "woo": > [1] -1 > ------------------------------------------------------------------------- > > Thank you for your attention. > -- > > Peter Ruckdeschel > > ______________________________________________ > R-devel@stat.math.ethz.ch mailing list > https://www.stat.math.ethz.ch/mailman/listinfo/r-devel-- John M. Chambers jmc@bell-labs.com Bell Labs, Lucent Technologies office: (908)582-2681 700 Mountain Avenue, Room 2C-282 fax: (908)582-3340 Murray Hill, NJ 07974 web: http://www.cs.bell-labs.com/~jmc
John Chambers
2003-Nov-20 16:10 UTC
[Rd] Was: setValidity and "initialize" method conflict ? [inR-help]
John Chambers wrote: .....................> > > > By the way, in the validity method you should not return a call to > warning() as in your example. The validity method just returns a > character string describing the problem.Sorry, I misread the example, the "warning" was just in the character string. Still, might be confusing since the result is normally an error, rather than a warning. John>-- John M. Chambers jmc@bell-labs.com Bell Labs, Lucent Technologies office: (908)582-2681 700 Mountain Avenue, Room 2C-282 fax: (908)582-3340 Murray Hill, NJ 07974 web: http://www.cs.bell-labs.com/~jmc