Skip to content

S4: what to put in initialize, validity and constructor?

4 messages · Christophe Genolini, Sklyar, Oleg (London), Oleg Sklyar

#
Hi the list,

I have some trouble using validity, intialize and the constructor. More 
precisely, what should go where?
Here is a toy exemple (seams long, but the code is very simple):

I want to define an object with two slots a and b with the properties that
b will be either empty or the scare of a. Example of valid object :
  a=  b=
  a=2 b=
  a=3 b=9

So I define my object and the validity function :

setClass(
    "A",
    representation(a="numeric",b="numeric"),
    validity=function(object){
        cat("Validity\n")
        if(length(object at b)!=0){
            if(length(object at a)==0){stop("Can not have empty a and non 
emty b")}else{}
            if(object at a^2!=object at b){stop("b is not the scare of a")}else{}
        }else{}
        return(TRUE)
    }
)

It works:

new("A")
new("A",a=2,b=4)
try(new("A",b=4))
new("A",a=2)
try(new("A",a=2,b=3))


Then I define the initialize function. When b is givent but not a, the 
initialise function set a to sqrt(b).

setMethod(
    "initialize",
    "A",
    function(.Object,a,b){
        if(missing(a)&!missing(b)){
            .Object at b <- b
            .Object at a <- sqrt(b)
        }else{}
        if(!missing(a)&missing(b)){
            .Object at a <- a
        }else{}
        if(!missing(a)&!missing(b)){
            .Object at a <- a
            .Object at b <- b
        }else{}
        validObject(.Object)
	return(.Object)
    }
)

It is fine:

new("A")
new("A",a=2,b=4)
new("A",b=9)
new("A",a=2)
try(new("A",a=2,b=3))


Then I want to set the constructor

A <- function(a,b){
    return(new("A",a,b))
}

But this does not work:
A()
A(a=2,b=4)
A(b=9)
A(a=2)


The following does not work either:

A <- function(a=numeric(),b=numeric()){
    return(new("A",a,b))
}

A()
A(a=2,b=4)
A(b=9)
A(a=2)

So is there a way to define the constructor A without dealing again 
with all the missing&missing staff like in initialize?

Christophe
#
setClass("A",
  representation(a="numeric",b="numeric"),
  validity = function(object) {
    if (length(object at a)!=length(object at b))
      return("different lengths of a and b")
    if (length(object at a)==0)
      return("object length is zero")
    TRUE
  }
)

Do not change initialize!

Define constructors:

setGeneric("A", function(a,b,...) standardGeneric("A"))

setMethod("A", signature(a="missing",b="missing"),
  function(a,b,...) A(as.numeric(1:10),...) ## calls the one below
)

setMethod("A", signature(a="A",b="missing"),
  function(a,b,...) a
)

setMethod("A", signature(a="ANY",b="ANY"),
  function(a,b,...) new("A",a=as.numeric(a),b=as.numeric(b),...)
)

setMethod("A", signature(a="ANY",b="missing"),
  function(a,b,...) A(a,a,...) ## Calls the one above
)

etc.

In words:
1) validity should return a character in case of errors
2) default initializer usually does the job
3) define constructors as methods to allow different signatures and 
   conversions from other classes
4) If you derive your class from numeric, rather than add slots,
   the performance will be much better and you will get default
   behaviour of numeric, i.e.

setClass("A",
  representatiom("numeric", b="numeric") etc

Dr Oleg Sklyar
Technology Group
Man Investments Ltd
+44 (0)20 7144 3803
osklyar at maninvestments.com
**********************************************************************
The contents of this email are for the named addressee(s...{{dropped:22}}
#
As I sat, this is a toy example. In my real example, initialize does a 
lot of things like calculation of quality indice (b is not the scare of 
a, but B1, B2 and B3 are the the within matrix of A after imputation 
with 3 differents methods), giving names to some matrix column and so 
on. So I seams costfull to not use an initialize.
#
cgenolin at u-paris10.fr wrote:
This all can be done in one of the constructors, which is then called by 
the other, as in my example below. I do not see a contradiction.