-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can we eliminate next_method()
?
#110
Comments
Maybe we could make # S3 method
`[.my_class` <- function(x, i) {
new_my_class(NextMethod(), x = attr(x, "x"), y = attr(x, "y"))
}
# Equivalent R7 method
method(`[`, my_class) <- function(x, i) {
new_my_class(method_call(R7_object), x = x@x, y = x@y)
} (Would need to think about the syntax for multi-dispatch methods; maybe using a named list? Can you supply just one of the arguments and leave the others to be looked up using the usual rules?) This has the advantage of being crystal clear about which method you want to call, and I think adds relatively little work since when you write Would need to verify that this also solves #119. I think it might just work because this already works: library(R7)
foo <- new_generic("foo", signature = "x")
method(foo, "character") <- function(x, y, ...) {
rlang::enquo(y)
}
foo("z", y = x + 1)
#> <quosure>
#> expr: ^x + 1
#> env: global Created on 2021-11-14 by the reprex package (v2.0.1) (presumably because we're somehow short circuiting a layer of promise creation that's normally a bad idea, but makes sense here) |
I think what Jan (or a compiler) would like is to know at the call site which method is being called, so that would be both the generic and the signature. Something like Maybe if we had some syntax for up-casting? For example, in S4 one can up-cast (strip off the subclass parts) with |
@lawremi my concern with replacing method(`[`, my_class) <- function(x, i, ..., a = 1, b = 2, c = 3) {
new_my_class(method_call(R7_object), x = x@x, y = x@y)
}
# vs
method(`[`, my_class) <- function(x, i, ..., a = 1, b = 2, c = 3) {
parent <- upcast(x, R7_object)
new_my_class(parent[x, i, ..., a = a, b = b, c = c], x = x@x, y = x@y)
} (the example doesn't quite work here with In my experience, remembering to pass along all the additional arguments is a common source of error. That said, in my approach, it's not clear how you avoiding passing along arguments that only exist on this method, not the parent method, or the generic. Maybe |
S4 has a utility called |
Yeah, that's a good point. Maybe a better solution would be an RStudio add-in (or similar) that could auto-generate the call for you? (And maybe mark it in some way that it could be later checked for consistency so that if you add a new argument to the method it's harder to forget to update the next method call?) |
For the purposes of discussion, I think these are the four options we've described above: library(R7)
foo <- new_class("foo", "character", properties = c(x = "numeric", y = "numeric"))
# like S3: 100% magical
method("[", "foo") <- function(x, i, ...) {
result <- next_method()
foo(result, x = x@x, y = y@y)
}
# Reduce magic by making superclass explicit
method("[", "foo") <- function(x, i, ...) {
resut <- next_method("character")
foo(result, x = x@x, y = y@y)
}
# like S4: up cast and then use helper to re-call generic
method("[", "foo") <- function(x, i, ...) {
result <- call_generic(up_cast(x, "character"))
foo(result, x = x@x, y = y@y)
}
# 100% explicit: up cast and re-call generic
method("[", "foo") <- function(x, i, ...) {
result <- up_cast(x, "character")[i = i, ...]
foo(result, x = x@x, y = y@y)
} |
Notes from meeting: What does # 100% explicit: up cast and re-call generic
method("[", "foo") <- function(x, i, ...) {
result <- next_method(x, "[", "character")(i = i, ...)
foo(result, x = x@x, y = y@y)
} Would be useful to look at how CLOO/Dylan do next method. Need to balance human needs vs implementation needs vs static analysis need. What happens when class hierarchy changes? Do you want to be forced to reconsider every How to handle missing arguments? How to handle tidy eval (#119)? Would it be better to enforce lock down (sealing) of class hierarchy at some time so that next method could be analysed statically? |
next_method()
?
Notes to self: Needs to happen after #137. If we don't want to create a copy, can start with something like below that is coupled with special handling in the code that goes from an object to a class string. up_cast <- function(object, class) {
# class must be R7.
# class must be a super class of object's class
# avoid creating a copy
out <- list(object = object, class = class)
attr(out, "class") <- "r7_upclass"
out
} |
As I mentioned on another issue, it's important that the modification to the class attribute only lasts for the first dispatch. If we want to avoid NSE, that probably means storing |
I wonder if we should make |
(Placeholder issue based on discussion in meeting today).
Or at least reduce the dynamism as much as possible? How does Julia get around it?
The text was updated successfully, but these errors were encountered: