From wolski at molgen.mpg.de  Mon Oct 11 10:36:25 2004
From: wolski at molgen.mpg.de (Witold Eryk Wolski)
Date: Mon Oct 11 10:36:46 2004
Subject: [Rd] Problem with _new_ if class "lm" in object representatio n.
In-Reply-To: <415DBE3F.D3DA3FB7@research.bell-labs.com>
References: <18D602BD42B7E24EB810D6454A58DB900A29BB79@ibfftce505.de.ad.drkw.net>		<415BFD9F.2080101@molgen.mpg.de>
	<6.0.1.1.2.20040930145247.01faaec0@stat4ux.stat.ucl.ac.be>
	<415DBE3F.D3DA3FB7@research.bell-labs.com>
Message-ID: <416A4609.5080602@molgen.mpg.de>

Hi,

Thanks to all of you for helpfull sugestions.


This weekend I found a manuscript by R. Gentlemen which discussed 
similar topics:
http://www.stat.auckland.ac.nz/S-Workshop/Gentleman/container.pdf


Yours,





John Chambers wrote:

>Eric Lecoutre wrote:
>  
>
>>Hi,
>>
>>For your lm problem, you could begin to create a virtual class that accepts
>>either NULL or a lm object:
>>
>> > setClassUnion("mylm", c("NULL","lm"))
>> > setClass("foo", representation(x="numeric", y="mylm"))
>> > new("foo",x=1,y=NULL)
>>
>>Then, you have to check the content of slot y in any function that will
>>manipulate objects of class "foo":
>>
>>         setMethod("show","foo",function(object)
>>         {
>>         cat("\n object of class foo")
>>         if (!is.null(object@y)) cat(" does have a lm object in slot y!")
>>         })
>>    
>>
>
>This is OK, but it illustrates why it would _not_ be a good idea to
>allow NULL values automatically for an arbitrary class.  The
>implementation here says that the "y" slot can be either a NULL or an
>"lm" object.  That is a different statement from saying that "y" must be
>an "lm" object.
>
>Either approach could make sense.  But what one really wants (in any
>definiton of a new class) is to match the actual definition to the
>intended meaning.
>
>With your suggestion, the designer of class "foo" is basically passing
>on to the implenters of methods the responsibility to check for a NULL
>"y" slot.  If it makes sense for legitimate "foo" objects to exist that
>have a NULL "y" slot, then that extra work is part of the design of the
>"foo" class.  Your definition of the class essentially says that the
>"lm" model is an optional part of the object.
>
>But if in fact it _only_ makes sense for the object to have a true
>model, then one should not define a class that conflicts with the
>intended meaning.   There was no indication in the initial question that
>NULL made sense.  If we're just introducing the NULL possibility as a
>programming hack, that's not really a good idea.
>
>The other approach is to insist that the computations creating a "foo"
>object generate a valid "lm" object, if the user didn't supply one. 
>Then methods for "foo" objects are not required to check.  One way to
>make the stricter approach work would be to have a method for
>initialize() for class "foo" that generated a model from the other slots
>in the object.
>
>For example, the class might represent "x" and "y" data, and a model
>that by default was the linear model for y~x.  Something like the
>following would implement that idea:
>
>setClass("withLm", representation(x="numeric", y="numeric", model =
>"lm"))
>
>setMethod("initialize", "withLm",
>          function(.Object, x = numeric(), y = numeric(), model = NULL)
>{
>              if(is.null(model))
>                  model <- lm(y ~ x)
>              callNextMethod(.Object, x=x, y=y, model=model)
>          }
>          )
>
>
>
>(unfortunately, lm() does not allow fitting vectors of length 0, so if
>this were a real example there are a few boundary cases to consider ;-)
>
>
>  
>
>>Eric
>>
>>At 14:35 30/09/2004, Witold Eryk Wolski wrote:
>>    
>>
>>>Hi,
>>>
>>>But "any" rises some other problems well known from S3. One has "any" for
>>>"free" in S3. You don't need S4. . But I know how "if" polluted
>>>functions  look like in S3. They are hard to understand and  to maintain.
>>>Hence I am quite happy to use S4.
>>>Type-checking is usefull if you program with data. Also if you are on the
>>>"C side" of the object. A further problem which I have with "any" is, that
>>>lm="any" in setClass tells you exactly ANYthing (and you are back in S3).
>>>And thats not what I like.*
>>>Hence, I do not want to use any in this case.
>>>
>>>I think that allowing to assing NULL to a slot will solve some problems
>>>which I have with S4 so far.
>>>
>>>a) How to express that an a slot content was not assigned so far? J.C.
>>>suggest to use character(0), lm(1~1) etc. The problem I have with
>>>insterting lm(1~1) in slot mod in my class Ctest are that I have 100000
>>>instances of object Ctest. At initialization everyone contains an object
>>>lm(1~1). But please  note the following.
>>>
>>>      
>>>
>>>>x<-lm(1~1)
>>>>object.size(x)
>>>>        
>>>>
>>>[1] 6388
>>>      
>>>
>>>>object.size(NULL)
>>>>        
>>>>
>>>[1] 0
>>>
>>>Unfortunately S4 do not have references. Hence, I can not store a
>>>reference to a single instance of lm(1~1) .
>>>
>>>Exactly the same problems I have if I want to "delete" an object. For
>>>example you like to have a slot  which stores some data which is important
>>>if the object is in one state. But if the state of the object changes you
>>>do not need that data anymore. Hence, you would like to delete it to get
>>>storage.  You can only do it if you have like you suggest "any", but the
>>>consequence is "if" polluted code, or using slot(obj,"mod",check=FALSE)<- NULL.
>>>
>>>But the documentation for slot states.
>>>check: " You should never set this to 'FALSE' in normal
>>>         use, since the result can create invalid objects. "
>>>
>>>
>>>b) The Problem which I have writing intitialization functions like
>>>suggested by J.C  is:  Imagine you have an object with twenty slots. You
>>>have to write and initialize function with approximately 20 "if"'s. One of
>>>the contribution of S4, as mentioned above, is to help you to avoid
>>>writing such "if" polluted functions. But as I sometimes forget any role
>>>has it's exceptions. So I can live with one function looking ugly in S4
>>>instead of having all functions "if" polluted like in case of S3.  The
>>>only consequence so far is that I try to avoid to write initialize
>>>functions. I do it only in some rare very special cases.
>>>
>>>The NULL exception in slot assignement will allow me object initialization
>>>using just "new" without providing a "if" polluted function initialize.
>>>
>>>      
>>>
>>>>setClass("bar")
>>>>        
>>>>
>>>[1] "bar"
>>>      
>>>
>>>>setClass("foo", representation(x="numeric", y="bar"))
>>>>        
>>>>
>>>[1] "foo"
>>>      
>>>
>>>>new("foo", x=1)
>>>>        
>>>>
>>>Error in validObject(.Object) : Invalid "foo" object: Invalid object for
>>>slot "y" in class "foo": got class "NULL", should be or extend class "bar"
>>>      
>>>
>>>Are there S4 inherent solutions to this questions?
>>>
>>>
>>>Yours.
>>>/E
>>>
>>>*(I would rather compare "any" to the Object class then to null in java.
>>>It has a different function.)
>>>
>>>Pfaff, Bernhard wrote:
>>>
>>>      
>>>
>>>>>Hi,
>>>>>
>>>>>Thanks a lot for pointing me to setOldClass().
>>>>>
>>>>>What is exactly the point against it, to allow NULL to be a special case
>>>>>which can be assigned to any slot? I think in java one can assing null
>>>>>to any slot (I do not like java but not because of that).
>>>>>I am asking because for some objects it may be hard to define something
>>>>>equivalent to numeric(0). And even lm(1~1) is not that what I am looking
>>>>>for. I would like to have the case
>>>>>of an unassigned slot (Just think about storage?) even to the expense
>>>>>checking every time if the slot is not null.
>>>>>
>>>>>          
>>>>>
>>>>Hello Eryk,
>>>>
>>>>how about "ANY" and checking where suitable/needed if the passed object for
>>>>"mod" is of class "lm" at a later stage in your code, like in:
>>>>
>>>>setClass("Ctest"
>>>>        ,representation(
>>>>                test="character"
>>>>                ,bla="character"
>>>>                ,mod="ANY"              )
>>>>        )
>>>>
>>>>test1 <- new("Ctest",mod=lm(1~1))
>>>>is(test1@mod, "lm")
>>>>
>>>>test2 <- new("Ctest",test="bla")
>>>>is(test2@mod, "lm")
>>>>
>>>>test3 <- new("Ctest",bla="brum")
>>>>is(test3@mod, "lm")
>>>>
>>>>test4 <- new("Ctest",test="bla",bla="brum")
>>>>is(test4@mod, "lm")
>>>>
>>>>From there on you could use stop() or warning() or whatever you want to
>>>>return to the user as information which class mod should belong to.
>>>>
>>>>HTH,
>>>>Bernhard
>>>>
>>>>        
>>>>
>>>______________________________________________
>>>R-devel@stat.math.ethz.ch mailing list
>>>https://stat.ethz.ch/mailman/listinfo/r-devel
>>>      
>>>
>>Eric Lecoutre
>>UCL /  Institut de Statistique
>>Voie du Roman Pays, 20
>>1348 Louvain-la-Neuve
>>Belgium
>>
>>tel: (+32)(0)10473050
>>lecoutre@stat.ucl.ac.be
>>http://www.stat.ucl.ac.be/ISpersonnel/lecoutre
>>
>>If the statistics are boring, then you've got the wrong numbers. -Edward
>>Tufte
>>
>>______________________________________________
>>R-devel@stat.math.ethz.ch mailing list
>>https://stat.ethz.ch/mailman/listinfo/r-devel
>>    
>>
>
>  
>


-- 
Dipl. bio-chem. Witold Eryk Wolski         
MPI-Moleculare Genetic
Ihnestrasse 63-73 14195 Berlin                 _
tel: 0049-30-83875219                 __("<   'v'
http://www.molgen.mpg.de/~wolski      \__/   /   \
mail: witek96@users.sourceforge.net    ^^     w w
      wolski@molgen.mpg.de


[Rd] Problem with _new_ if class "lm" in object representatio n.
Witold Eryk Wolski