From hpages at fhcrc.org  Fri Apr  6 20:01:58 2007
From: hpages at fhcrc.org (Herve Pages)
Date: Fri, 06 Apr 2007 11:01:58 -0700
Subject: [Rd] Problem with S4 inheritance: unexpected re-initialization?
In-Reply-To: <6phfy7dlw4p.fsf@gopher4.fhcrc.org>
References: <46112187.3090009@aon.at>
	<4612CCAB.1080809@fhcrc.org>	<4613BE1D.5000507@aon.at>
	<4613F186.1060507@fhcrc.org>	<46152B35.2070200@aon.at>
	<6phfy7dlw4p.fsf@gopher4.fhcrc.org>
Message-ID: <46168B16.4090703@fhcrc.org>

Martin,

Martin Morgan wrote:
> The funny effect where class(object) seems to trigger construction of
> a new object is lazy evaluation -- the 'object' argument to
> setValidity is not evaluated until needed, i.e., until class(object)
> (anything would trigger this, including force(object)); only then do
> you see the attempt to create the new object of the previous
> paragraph.

The fact that you can't predict the number of times the "initialize"
method will be called is problematic. Here is a simple example
where "initialize-A" increments a global counter to keep track of the
number of A-objects:

  A.GLOBALS <- new.env(parent=emptyenv())
  A.GLOBALS[["nobjs"]] <- 0L

  setClass("A",
    representation(a="character"),
    prototype(a="a0")
  )
  setMethod("initialize", "A",
    function(.Object, ...) {
        cat("------initialize:A------\n")
        A.GLOBALS[["nobjs"]] <- A.GLOBALS[["nobjs"]] + 1
        cat("A-object #", A.GLOBALS[["nobjs"]], "\n", sep="")
        callNextMethod()
    }
  )
  setValidity("A",
    function(object) {
        cat("------setValidity:A------\n")
        tmp <- class(object)
        TRUE
    }
  )

  setClass("B",
    contains="A",
    representation(b = "character")
  )
  setMethod("initialize", "B",
    function(.Object, ...) {
        cat("------initialize:B------\n")
        callNextMethod()
    }
  )
  setValidity("B",
    function(object) {
        cat("------setValidity:B------\n")
        TRUE
    }
  )

Let's try it:

  > b1 <- new("B")
  ------initialize:B------
  ------initialize:A------
  A-object #1
  > A.GLOBALS[["nobjs"]]
  [1] 1

  > b1 <- new("B", b="hello")
  ------initialize:B------
  ------initialize:A------
  A-object #2
  ------setValidity:A------
  ------initialize:A------
  A-object #3
  ------setValidity:B------
  > A.GLOBALS[["nobjs"]]
  [1] 3

Shouldn't the "initializing" ("constructor" in other languages) code be executed
exactly 1 time per object instanciation? Something that the programmer can simply
rely on, whatever this code contains and whatever the internal subtilities of the
programming lamguage are?

Cheers,
H.



[Rd] Problem with S4 inheritance: unexpected re-initialization?
Herve Pages