Ein eingebundener Text mit undefiniertem Zeichensatz wurde abgetrennt. Name: nicht verf?gbar URL: <https://stat.ethz.ch/pipermail/r-help/attachments/20101028/d7e0cc89/attachment.pl>
overloading the generic primitive functions "+" and "["
7 messages · Mark Heckmann, Christofer Bogaso, Martin Morgan +2 more
On Thu, Oct 28, 2010 at 9:31 AM, Mark Heckmann <mark.heckmann at gmx.de> wrote:
How can I add a new method to the generic function "[" or "+" I want to create a S3 and S4 class that will use the "[" and "+" method in a different way. How can I overload the generic primitive "[" or "+" so the method dispatch will work correctly for my class? I saw an example of this in the ggplot2 package where different objects are joined using the "+" primitive. Still, I could not figure out how to do that. Can someone give a small code example to show how that works?
With S3 method stuff, to override "+" its as easy as writing Ops.{class}:
> a="hello"
> b="world"
> a+b
Error in a + b : non-numeric argument to binary operator
> class(a)="ss"
> class(b)="ss"
> Ops.ss=function(e1,e2){paste(e1,e2)}
> a+b
[1] "hello world"
better make sure I haven't broken anything:
> c=1
> d=2
> c+d
[1] 3 *phew*
The Ops function should really have a handler for all possible
operators (*, /, - etc) or fail with an error - see Ops.Date for
example.
With S4 classes... umm.. signatures... setMethod... setGeneric...
errr. something... representations... setClass this that... yeah.
Something like that.
Barry
Dear Barry, this is really interesting. However I could not understand
this line:
Ops.ss=function(e1,e2){paste(e1,e2)}
Where you have told R to behave "+" function differently when it faces
"ss" class?
What should be the ideal approach if I what to use "*" function?
Thanks,
On Thu, Oct 28, 2010 at 2:47 PM, Barry Rowlingson
<b.rowlingson at lancaster.ac.uk> wrote:
On Thu, Oct 28, 2010 at 9:31 AM, Mark Heckmann <mark.heckmann at gmx.de> wrote:
How can I add a new method to the generic function "[" or "+" I want to create a S3 and S4 class that will use the "[" and "+" method in a different way. How can I overload the generic primitive "[" or "+" so the method dispatch will work correctly for my class? I saw an example of this in the ggplot2 package where different objects are joined using the "+" primitive. Still, I could not figure out how to do that. Can someone give a small code example to show how that works?
?With S3 method stuff, to override "+" its as easy as writing Ops.{class}:
?> a="hello"
?> b="world"
?> a+b
?Error in a + b : non-numeric argument to binary operator
?> class(a)="ss"
?> class(b)="ss"
?> Ops.ss=function(e1,e2){paste(e1,e2)}
?> a+b
?[1] "hello world"
?better make sure I haven't broken anything:
?> c=1
?> d=2
?> c+d
?[1] 3 ? *phew*
The Ops function should really have a handler for all possible
operators (*, /, - etc) or fail with an error - see Ops.Date for
example.
With S4 classes... umm.. signatures... setMethod... setGeneric...
errr. something... representations... setClass this that... yeah.
Something like that.
Barry
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
On 10/28/2010 02:17 AM, Barry Rowlingson wrote:
On Thu, Oct 28, 2010 at 9:31 AM, Mark Heckmann <mark.heckmann at gmx.de> wrote:
How can I add a new method to the generic function "[" or "+" I want to create a S3 and S4 class that will use the "[" and "+" method in a different way. How can I overload the generic primitive "[" or "+" so the method dispatch will work correctly for my class? I saw an example of this in the ggplot2 package where different objects are joined using the "+" primitive. Still, I could not figure out how to do that. Can someone give a small code example to show how that works?
With S3 method stuff, to override "+" its as easy as writing Ops.{class}:
> a="hello" > b="world" > a+b
Error in a + b : non-numeric argument to binary operator
> class(a)="ss"
> class(b)="ss"
> Ops.ss=function(e1,e2){paste(e1,e2)}
> a+b
[1] "hello world" better make sure I haven't broken anything:
> c=1 > d=2 > c+d
[1] 3 *phew* The Ops function should really have a handler for all possible operators (*, /, - etc) or fail with an error - see Ops.Date for example. With S4 classes... umm.. signatures... setMethod... setGeneric... errr. something... representations... setClass this that... yeah. Something like that.
The more-or-less literal translation of your S3 to S4 is
setClass("SS", "character")
setMethod(Ops, c("SS", "SS"), function(e1, e2) paste(e1, e2))
Not so hard, eh? Though then like your S3 implementation this makes all
'Ops' (see ?Ops) the same for SS objects. For "+" alone
setMethod("+", c("SS", "SS"), function(e1, e2) paste(e1, e2))
One might typically use a group generic like Ops (or Arith for a narrow
set of operations in S4) when wanting to delegate to a slot of a class,
e.g.,
setClass("Person", representation(age="numeric"))
setMethod(Arith, c("Person", "Person"), function(e1, e2) {
callGeneric(e1 at age, e2 at age)
})
Phred = new("Person", age=32)
Phrank = new("Person", age=37)
Phred - Phrank
[1] -5
Phred * Phrank
[1] 1184 Martin
Barry
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
Computational Biology Fred Hutchinson Cancer Research Center 1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109 Location: M1-B861 Telephone: 206 667-2793
On Thu, Oct 28, 2010 at 2:12 PM, Martin Morgan <mtmorgan at fhcrc.org> wrote:
Not so hard, eh? Though then like your S3 implementation this makes all 'Ops' (see ?Ops)
Except you have to re-run the set* things every R session:
> setClass("SS", "character")
> setMethod(Ops, c("SS", "SS"), function(e1, e2) paste(e1, e2))
> a=new("SS","hello")
> b=new("SS","world")
> a+b
[1] "hello world"
> q()
Save workspace image? [y/n/c]: y
...start R again...
[Previously saved workspace restored]
> a=new("SS","hello")
> b=new("SS","world")
> a+b
Error in a + b : non-numeric argument to binary operator
It seems the SS class is preserved but the method definition isn't.
Otherwise new("SS","hello") fails.
That's one of the things that confuses me about S4 - its use of
invisible global things. ls(all.names=TRUE) shows me the bits:
> ls(all.names=TRUE)
[1] "a" ".__C__SS" ".requireCachedGenerics"
It seems that .__C__SS is the class definition, and the
.requireCachedGenerics seems to imply I've done something with 'Ops':
> .requireCachedGenerics
[[1]]
[1] "Ops"
but doesn't actually store and restore my definition.
A bug? I dunno. Version 2.10.1 if anyone cares. I don't. I'll just go
back to my S3 method which is just as simple and works when I restore
the .RData I saved things to. Each to their own!
Barry
On Thu, Oct 28, 2010 at 12:14 PM, Christofer Bogaso
<bogaso.christofer at gmail.com> wrote:
Dear Barry, this is really interesting. However I could not understand
this line:
Ops.ss=function(e1,e2){paste(e1,e2)}
Where you have told R to behave "+" function differently when it faces
"ss" class?
What should be the ideal approach if I what to use "*" function?
You can get the character string of the operator from '.Generic', for example:
Ops.ss=function(e1,e2){
if(.Generic=="+"){
return(paste(e1,e2))
}
if(.Generic=="*"){
return(rep(e1,e2))
}
stop("No definition for ",.Generic)
}
Giving:
> a*5
[1] "hello" "hello" "hello" "hello" "hello"
> a+"world"
[1] "hello world"
> a/2
Error in Ops.ss(a, 2) : No definition for /
Note how S3 methods are dispatched only by reference to the first
argument (on the left of the operator). I think S4 beats this by
having signatures that can dispatch depending on both arguments.
Barry
Note how S3 methods are dispatched only by reference to the first argument (on the left of the operator). I think S4 beats this by having signatures that can dispatch depending on both arguments.
That's somewhat of a simplification for primitive binary operators. R actually looks up the method for both input classes, and returns a error if they are different. Hadley
Assistant Professor / Dobelman Family Junior Chair Department of Statistics / Rice University http://had.co.nz/