Re: [Rd] setIs and method dispatch in S4 classes

2006-04-10 Thread Peter Ruckdeschel
Hi Seth ,

thank you for your reply.

Seth Falcon  [EMAIL PROTECTED] writes:

Peter Ruckdeschel [EMAIL PROTECTED] writes:
  

 ## now: B00 mother class to B01 and B02, and again B02 contains B01 by
 setIs:
 setClass(B00, representation(a=numeric))
 setClass(B01, representation(a=numeric,b=numeric), contains= B00)
 setClass(B02, representation(a=numeric,d=numeric), contains= B00)
 setIs(B02,B01,coerce=function(obj){new(B01, [EMAIL PROTECTED], [EMAIL 
 PROTECTED])},
replace=function(obj,value){new(B01, [EMAIL PROTECTED], [EMAIL 
 PROTECTED])})

 # now two + methods  for B00 and B01
 setMethod(+, signature=c(B00,B00), function(e1,e2)[EMAIL PROTECTED]@a})
 setMethod(+, signature=c(B01,B01), function(e1,e2)[EMAIL PROTECTED]@b})

 x1=new(B02, a=1, d=2)
 x2=new(B02, a=1, d=3)

 x1+x2 ## 2 --- why?



My impression from reading over the man page for setIs, is that it
isn't intended to be used to override the existing inheritance
hierarchy.  It also mentions that the return value is the extension
info as a list, so that could also be useful in understanding what
setIs is doing.  Here's the output for your example:

Slots:
  
Name:a   d
Class: numeric numeric

Extends: 
Class B00, directly
Class B01, directly, with explicit coerce

Use the contains arg of setClass to define the superclasses.  With the
contains arg, the order determines the precedence for method lookup.
But I suspect you know that already.  
  

Yes, I have been aware of this, thank you.

 Is there a possibility to force usage of the B01 method /without/
 explicitely coercing x1,x2 to B01, i.e. interfere in the dispatching 
 precedence, telling R somehow  (by particular arguments for setIs ?)  
 to always use the is-relation defined by setIs first before mounting 
 the hierarchy tree?


 Perhaps explaining a bit more about what you are trying to accomplish
 will allow someone to provide a more helpful suggestion than mine :-)

In the real context, B00 stands for a class AbscontDistribution,
which implements absolutely continuous (a.c.) distributions. B01 is
class Gammad which implements Gamma distributions, and B02 is
class Exp which implements exponential distributions. The method
still is +, but interpreted as convolution.

For  a.c. distributions, the default method is an FFT-based numerical
convolution algorithm, while for Gamma distributions (with the same
 scale parameter), analytic, hence much more accurate convolution
formulas are used. For Exp, I would tell R that it also 'is' a Gammad
distribution by a call to setIs and use the Gammad-method.

Of course, I could also declare explicitly + methods for signatures
c(Exp, Exp), c(Exp, Gammad), and c(Gammad, Exp)  in
which I would then use as(.) to coerce Exp to Gammad
(and again the same procedure for further Gamma-methods). 

But, this would create an extra (3 or possibly much more) methods
to dispatch, and I doubt whether this really is the preferred
solution.

 If you know the inheritance structure you want before run-time, then
 I'm not seeing why you wouldn't just use the contains arg

I do not want to use the +  method for B00 for accuracy reasons
(see above).

The reason why I do not want to implement B01 (Gammad)
as mother class of B02 is that

(a) the slot structure is not identical --- in the real context Gamma
and Exp use different parametrizations ---
 + rate for Exp (cf ?rexp) and
 + shape for Gammad (cf rgamma)

(b) also class Weibull could be used as mother class to Exp,
and I do not want to decide whether the Weibull or the
Gamma is the (more) legitimate mother to Exp ;-) 

I know: 'contains' could be a vector of classes ---
c(Gammad, Weibull)  --- but then which would be
the  correct slot structure for Exp the one of Gammad
or the one of Weibull ?
My context is a bad example, Gammad, Weibull
do have the same slots, but more generally this /is/ an issue...
 
--- So my guess was to rather implement two 'is'-relations
( Exp 'is' Gammad  and  Exp 'is' Weibull)
declared by 'setIs' , and then on run time let the
dispatching mechanism decide whether to use
a Gamma or a Weibull method.

But maybe there is a better solution ?
Any suggestions are welcome.

 And if you want to force certain behavior at run-time, then I don't
 see what's wrong with an explicit coercion using as(foo, bar).

If you have two objects E1, E2 of class Exp (with the same rate)
you (or the user for whom we provide these classes)  rather want to
call + by E1 + E2  than
by  as(E1, Gammad) + as(E2,Gammad)
...

Anyway, thank you for your help

Peter

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] setIs and method dispatch in S4 classes

2006-04-10 Thread John Chambers
 From your description of the application, it sounds like you would be 
better off just forcing + to behave as you want.  Using inheritance is 
a much more powerful mechanism  can introduce results you don't want, 
as it seems to have in this case.

An important point about using inheritance is that the subclass is a 
asserted to be substitutable for the superclass for ALL purposes.  This 
applies whether using contains= or  setIs().

When the focus is on a particular function, it's usually better to 
implement methods for that function, maybe along with setAs() 
methods--not setIs().

It seems likely that such a solution would be cleaner in design, not to 
mention that it would likely work.  (see also suggestion below)


Peter Ruckdeschel wrote:

Hi Seth ,

thank you for your reply.

Seth Falcon  [EMAIL PROTECTED] writes:

  

Peter Ruckdeschel [EMAIL PROTECTED] writes:
 



## now: B00 mother class to B01 and B02, and again B02 contains B01 by
setIs:
setClass(B00, representation(a=numeric))
setClass(B01, representation(a=numeric,b=numeric), contains= B00)
setClass(B02, representation(a=numeric,d=numeric), contains= B00)
setIs(B02,B01,coerce=function(obj){new(B01, [EMAIL PROTECTED], [EMAIL 
PROTECTED])},
   replace=function(obj,value){new(B01, [EMAIL PROTECTED], [EMAIL 
 PROTECTED])})

# now two + methods  for B00 and B01
setMethod(+, signature=c(B00,B00), function(e1,e2)[EMAIL PROTECTED]@a})
setMethod(+, signature=c(B01,B01), function(e1,e2)[EMAIL PROTECTED]@b})

x1=new(B02, a=1, d=2)
x2=new(B02, a=1, d=3)

x1+x2 ## 2 --- why?
   

  

My impression from reading over the man page for setIs, is that it
isn't intended to be used to override the existing inheritance
hierarchy.  It also mentions that the return value is the extension
info as a list, so that could also be useful in understanding what
setIs is doing.  Here's the output for your example:

   Slots:
 
   Name:a   d
   Class: numeric numeric
   
   Extends: 
   Class B00, directly
   Class B01, directly, with explicit coerce

Use the contains arg of setClass to define the superclasses.  With the
contains arg, the order determines the precedence for method lookup.
But I suspect you know that already.  
 



Yes, I have been aware of this, thank you.

  

Is there a possibility to force usage of the B01 method /without/
explicitely coercing x1,x2 to B01, i.e. interfere in the dispatching 
precedence, telling R somehow  (by particular arguments for setIs ?)  
to always use the is-relation defined by setIs first before mounting 
the hierarchy tree?
   

  

Perhaps explaining a bit more about what you are trying to accomplish
will allow someone to provide a more helpful suggestion than mine :-)



In the real context, B00 stands for a class AbscontDistribution,
which implements absolutely continuous (a.c.) distributions. B01 is
class Gammad which implements Gamma distributions, and B02 is
class Exp which implements exponential distributions. The method
still is +, but interpreted as convolution.

For  a.c. distributions, the default method is an FFT-based numerical
convolution algorithm, while for Gamma distributions (with the same
 scale parameter), analytic, hence much more accurate convolution
formulas are used. For Exp, I would tell R that it also 'is' a Gammad
distribution by a call to setIs and use the Gammad-method.

Of course, I could also declare explicitly + methods for signatures
c(Exp, Exp), c(Exp, Gammad), and c(Gammad, Exp)  in
which I would then use as(.) to coerce Exp to Gammad
(and again the same procedure for further Gamma-methods). 

But, this would create an extra (3 or possibly much more) methods
to dispatch, and I doubt whether this really is the preferred
solution.
  

Why not?  And you can avoid some of the extra methods by defining a 
virtual class that is the union of the classes for which you want the 
new methods.

Something like (untested code!)

setClassUnion(analyticConvolution, c(Exp, Gammad))
setMethod(+, c(analyticConvolution, analyticConvolution), )

  

If you know the inheritance structure you want before run-time, then
I'm not seeing why you wouldn't just use the contains arg



I do not want to use the +  method for B00 for accuracy reasons
(see above).

The reason why I do not want to implement B01 (Gammad)
as mother class of B02 is that

(a) the slot structure is not identical --- in the real context Gamma
and Exp use different parametrizations ---
 + rate for Exp (cf ?rexp) and
 + shape for Gammad (cf rgamma)

(b) also class Weibull could be used as mother class to Exp,
and I do not want to decide whether the Weibull or the
Gamma is the (more) legitimate mother to Exp ;-) 

I know: 'contains' could be a vector of classes ---
c(Gammad, Weibull)  --- but then which would be
the  correct slot structure for Exp the one of Gammad
or the one of Weibull ?
My context is a bad example, Gammad, Weibull
do have the same slots, but more generally this 

Re: [Rd] setIs and method dispatch in S4 classes

2006-04-10 Thread Seth Falcon
Hi John,

I found your comments helpful, even though this isn't _my_ question.
But now I have one of my own :-)

John Chambers [EMAIL PROTECTED] writes:
Of course, I could also declare explicitly + methods for signatures
c(Exp, Exp), c(Exp, Gammad), and c(Gammad, Exp)  in
which I would then use as(.) to coerce Exp to Gammad
 (and again the same procedure for further Gamma-methods). 

But, this would create an extra (3 or possibly much more) methods
to dispatch, and I doubt whether this really is the preferred
solution.
  

 Why not?  And you can avoid some of the extra methods by defining a
 virtual class that is the union of the classes for which you want the
 new methods.

 Something like (untested code!)

 setClassUnion(analyticConvolution, c(Exp, Gammad))
 setMethod(+, c(analyticConvolution, analyticConvolution),
 )

Why class union here and not an abstract superclass?  

If you own the Exp and Gammad classes, would an abstract superclass
work as well?  I think so.

However, if you don't own the Exp and Gammad classes, I can see that
the class union approach allows you the flexibility of defining a
superclass post-hoc.

I guess I have the sense that class unions are fancy/tricky (a number
of popular languages don't have that concept, AFAIK).  That isn't a
reason not to use them in a langauge that does support them, of
course.  

It is an interesting design question.  On the one hand, one could
argue for abstract superclasses when possible because they are less
tricky (and you need them when you want to share slots).  On the
other hand, the class union approach provides a more loosely coupled
design since members of the union don't have to know about each other.

Hmm, I think I understand class unions a lot better already.  Thanks.
If I'm terribly off-track, please let me know.  

+ seth

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] setIs and method dispatch in S4 classes

2006-04-10 Thread John Chambers
Seth Falcon wrote:

Hi John,

I found your comments helpful, even though this isn't _my_ question.
But now I have one of my own :-)

John Chambers [EMAIL PROTECTED] writes:
  

Of course, I could also declare explicitly + methods for signatures
c(Exp, Exp), c(Exp, Gammad), and c(Gammad, Exp)  in
which I would then use as(.) to coerce Exp to Gammad
(and again the same procedure for further Gamma-methods). 

But, this would create an extra (3 or possibly much more) methods
to dispatch, and I doubt whether this really is the preferred
solution.
 

  

Why not?  And you can avoid some of the extra methods by defining a
virtual class that is the union of the classes for which you want the
new methods.

Something like (untested code!)

setClassUnion(analyticConvolution, c(Exp, Gammad))
setMethod(+, c(analyticConvolution, analyticConvolution),
)



Why class union here and not an abstract superclass?  

If you own the Exp and Gammad classes, would an abstract superclass
work as well?  I think so.
  

Yes, as is said frequently of a certain other language There's more 
than one way to do it

My own feeling is that class unions are a convenient shorthand  clearer 
than explicitly defining the superclass and then having to establish the 
inheritance separately for the two subclasses.  Although the 
documentation mentions that they _must_ be used for classes you don't 
own, that's not their only purpose.

Virtual classes (ahem, I assume that's what you meant by abstract  
;-)) may or may not have slots of their own.   Creating a virtual class 
analyticConvolution and doing two setIs() calls would in fact be 
roughly equivalent to the setClassUnion, but not as clear, IMO.

If the superclass was really crucial to the model, that would make it 
more natural to have it explicitly in the contains= for the individual 
subclasses.  Here, though, it seems more like a computational 
convenience for a fairly small part of the overall package, so isolating 
it in a single setClassUnion() call seems more natural.

Obviously, a question of taste and style.

However, if you don't own the Exp and Gammad classes, I can see that
the class union approach allows you the flexibility of defining a
superclass post-hoc.

I guess I have the sense that class unions are fancy/tricky (a number
of popular languages don't have that concept, AFAIK).  That isn't a
reason not to use them in a langauge that does support them, of
course.  

It is an interesting design question.  On the one hand, one could
argue for abstract superclasses when possible because they are less
tricky (and you need them when you want to share slots).  On the
other hand, the class union approach provides a more loosely coupled
design since members of the union don't have to know about each other.

Hmm, I think I understand class unions a lot better already.  Thanks.
If I'm terribly off-track, please let me know.  

+ seth

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

  


[[alternative HTML version deleted]]

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] setIs and method dispatch in S4 classes

2006-04-07 Thread Vincent Carey 525-2265

as a fan of S4 i had a look at this; more definitive
replies are undoubtedly to come

 ## now: B00 mother class to B01 and B02, and again B02 contains B01 by 
 setIs:
 setClass(B00, representation(a=numeric))
 setClass(B01, representation(a=numeric,b=numeric), contains= B00)

the direct specification of containment in the next statement
is important for the dispatch process

 setClass(B02, representation(a=numeric,d=numeric), contains= B00)

if we omit the containment assertion your expectations are met

setClass(B02, representation(a=numeric,d=numeric))
setIs(B02,B01,coerce=function(obj){new(B01, [EMAIL PROTECTED], [EMAIL 
PROTECTED])},
   replace=function(obj,value){new(B01, [EMAIL PROTECTED], [EMAIL 
PROTECTED])})

two diagnostic steps that are illuminating are

getClass(B02)  under both approaches (with and without contains=B00
in definition of B02 class)

and

getMethods(+)  under both approaches

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel