From jmc at research.bell-labs.com  Thu Nov 20 15:53:54 2003
From: jmc at research.bell-labs.com (John Chambers)
Date: Thu Nov 20 15:53:49 2003
Subject: [Rd] Was: setValidity and "initialize" method conflict ? [in
	R-help]
References: <3FBBAD6C.2000803@uni-bayreuth.de>
Message-ID: <3FBCD582.F70EAC2B@research.bell-labs.com>

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


[Rd] Was: setValidity and "initialize" method conflict ? [in R-help]
John Chambers