R's UseMethod() does not dispatch on changed class() (PR#167)
I've done some editing to get things together (hopefully without changing the semantics)
On Thu, 15 Apr 1999, Prof Brian D Ripley wrote:
On Wed, 14 Apr 1999, Robert Gentleman wrote:
On Wed, 14 Apr 1999, Prof Brian D Ripley wrote:
On 15 Apr 1999, Peter Dalgaard BSA wrote:
Robert Gentleman <rgentlem@hsph.harvard.edu> writes:
I did not mean to imply that you were wrong, rather that the White Book can be read both ways (and it seems has been).
But, it as I understand it, UseMethod is supposed to call the method with the arguments the same as those that called the generic. You must evaluate x to figure out what method to call, but I don't see how you can change x (adding classes is changing it).
Then why are
UseMethod("foo")
UseMethod("foo", x)
different
and by the standard evaluation model, `object' is subject to lazy
evaluation. Nothing I can see in the White Book says otherwise. Indeed,
page 467 says the arguments are `re-matched by the standard rules'. It then
says `The method will see argument matches as it would if the user's call
had been directly to the method'. I think those claims are contradictory,
and in particular whichever way they are read suggest my pair of calls
should be the same.
[In S UseMethod("foo") is semantic shorthand for UseMethod("foo", <name of
first argument of caller>), according to the help page.]
Now, with my reading, the method will see the argument as it would
if the users call had been directly to the the method, coupled with
the later comment (top of p. 469) that for NextMethod you must take local
bindings for the arguments, yields
with UseMethod you don't take local bindings, the method gets what
the generic did, but it will rematch (argument names and positions
may have changed). That means you need to ignore what happened
inside of the generic.
Now, we have the variable definition problem raise it's head,
UseMethod("foo")
UseMethod("foo",x)
If the second version doesn't use the local binding of x then
UseMethod behaves differently, in terms of how it treats its arguments
than every other function (which is ok, we just need to be specific
about it).
So we have to make a decision, UseMethod does what S does (which is
fine) or it doesn't.
To make matters worse, in S it is a common mistake to have
foo <- function(x, ...) UseMethod("foo")
foo.lm <- function(y, ...) { .... }
and that change of name of argument causes re-evaluation. What happens in
R?
The standard argument matching system takes over. If there was an
argument y=blah, in the ... then it will get matched to y in foo.lm
even though something different was matched to x in the call to the
generic. I don't believe that a reevaluation takes place in either
situation. If x was evaluated and that is what is matched then we
look in the value side of the expression, see that it's there and
carry on. If we match to something new then the standard rules take
over.
Promises are basically cells with three slots, an unevaluated
expression, an environment in which to carry out the evaluation
of that expression and a value. When we want a value, we look in
the value slot first, if there is no value, we evaluate the
expression and stick the value into the value slot. So promises
should never be evaluated twice.
For those not bored, here is a difference between R and S that
we may not want.
bar<-function(w,...) {
UseMethod("bar")
}
bar.foo<-function(y, w) print(w)
x<-30
class(x)<-"foo"
Now in R,
bar(x,10)
[1] 10
bar(x,y=10)
[1] 30 attr(,"class") [1] "foo" Notice that if the arguments are not named we use default matching and that the symbolic name for the first argument in the generic is not carried over. In S bar(x,10) and bar(x,y=10) both evaluate to the same thing, [1] 30 attr(,"class") [1] "foo" it appears that the name w has been applied to the first argument and that is carried with it for subsequent evaluations. I'm not sure what you meant by "the change of name causes reevaluation, when I try
bar(x<-x+1)
I get, [1] 31 attr(, "class"): [1] "foo" [1] 31 attr(, "class"): [1] "foo" which is only one evaluation (and the same in R)
This makes an apparently small point, that generics should have the
same argument name as S, potentially rather important. I know of four
outstanding discrepancies:
R: deviance <- function (x, ...) UseMethod("deviance")
S: deviance <- function (x, ...) UseMethod("deviance")
and ditto for coef, fitted, residuals (which I had not realized, in part
because some of these only recently acquited defaults).
There are inconsistencies in the current R code: any objections if
I change these to uniformly follow S and use `object'?
Change to your hearts content. I think we want something that works and that makes sense.
What we do need is to get this documented! In particular, in R
?UseMethod
Class Methods
UseMethod(name)
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html Send "info", "help", or "[un]subscribe" (in the "body", not the subject !) To: r-devel-request@stat.math.ethz.ch _._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._