>>>>> brodie gaslam via R-devel >>>>> on Thu, 29 Apr 2021 01:04:01 +0000 (UTC) writes:
>> On Wednesday, April 28, 2021, 5:16:20 PM EDT, Gabriel Becker <gabembec...@gmail.com> wrote: >> >> Hi Antoine, >> >> I would say this is the correct behavior. S3 dispatch is solely (so far as >> I know?) concerned with the "actual classes" on the object. This is because >> S3 classes act as labels that inform dispatch what, and in what order, >> methods should be applied. You took the function class (ie label) off of >> your object, which means that in the S3 sense, that object is no longer a >> function and dispatching to function methods for it would be incorrect. >> This is independent of whether the object is still callable "as a function". >> >> The analogous case for non-closures to what you are describing would be for >> S3 to check mode(x) after striking out with class(x) to find relevant >> methods. I don't think that would be appropriate. > I would think of the general case to be to check `class(unclass(x))` on > strike-out. This would then include things such as "matrix", etc. > Dispatching on the implicit class as fallback seems like a natural thing > to do in a language that dispatches on implicit class when there is none. > After all, once you've struck out of your explicit classes, you have > none left! > This does happen naturally in some places (e.g. interacting with a > data.frame as a list), and is quite delightful (usually). I won't get > into an argument of what the documentation states or whether any changes > should be made, but to me that dispatch doesn't end with the implicit > class seems feels like a logical wrinkle. Yes, I can twist my brain to > see how it can be made to make sense, but I don't like it. > A fun past conversation on this very topic: > https://stat.ethz.ch/pipermail/r-devel/2019-March/077457.html Thank you, Gabe and Brodie. To the OP, Gabe's advice to *NOT* throw away an existing class is really important, and good code -- several examples in base R -- would really *extend* a class in such cases, i.e., function(x, ...) { ...... ans <- things.on(x, .....) class(ans) <- c("foo", class(x)) # ans } I don't have time to go in-depth here (teaching and other duties), but I want to point you to one important extra point, which I think you have not been aware: S3 dispatch *does* look at what you see from class() *but* has always done some extra things, notably for atomic and other *base* objects. There's always been a dedicated function in R's C code to do this, R_data_class2(), e.g., called from C usemethod() called from R's UseMethod(). Since R 4.0.0, we have provided R function .class2() to give the same result as the internal R_data_class2(), and hence show the classes (in the correct order!) which are really for S3 dispatch. The NEWS entry for that was \item New function \code{.class2()} provides the full character vector of class names used for S3 method dispatch. Best, Martin > Best, > B. >> Also, as an aside, if you want your class to override methods that exist >> for function you would want to set the class to c("foo", "function"), not >> c("function", "foo"), as you had it in your example. >> >> Best, >> ~G >> >> On Wed, Apr 28, 2021 at 1:45 PM Antoine Fabri <antoine.fa...@gmail.com> >> wrote: >> >>> Dear R devel, >>> >>> as.list() can be used on functions, but not if they have a S3 class that >>> doesn't include "function". >>> >>> See below : >>> >>> ```r >>> add1 <- function(x) x+1 >>> >>> as.list(add1) >>> #> $x >>> #> >>> #> >>> #> [[2]] >>> #> x + 1 >>> >>> class(add1) <- c("function", "foo") >>> >>> as.list(add1) >>> #> $x >>> #> >>> #> >>> #> [[2]] >>> #> x + 1 >>> >>> class(add1) <- "foo" >>> >>> as.list(add1) >>> #> Error in as.vector(x, "list"): cannot coerce type 'closure' to vector of >>> type 'list' >>> >>> as.list.function(add1) >>> #> $x >>> #> >>> #> >>> #> [[2]] >>> #> x + 1 >>> ``` >>> >>> In failing case the argument is dispatched to as.list.default instead of >>> as.list.function. >>> >>> (1) Shouldn't it be dispatched to as.list.function ? >>> >>> (2) Shouldn't all generics when applied on an object of type closure fall >>> back to the `fun.function` method before falling back to the `fun.default` >>> method ? >>> >>> Best regards, >>> >>> Antoine > ______________________________________________ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel