-
Notifications
You must be signed in to change notification settings - Fork 37
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
super()
while implementing a method on a class union
#493
Comments
Currently, However, you can still achieve what you want by calling # Approach 1: using `method()`
method(f, A_Child | B_Child) = \(x) {
parent_method <- method(f, S7_class(x)@parent) # Get method for A or B
parent_method(x)
}
# Approach 2: using `convert()`
method(f, A_Child | B_Child) = \(x) {
# parent_instance is an A or B
parent_instance <- convert(x, S7_class(x)@parent)
f(parent_instance) # Dynamically dispatch to method for A or B
## Return f(parent_instance), or
## maybe update x with f() parent method updated props
# props(x) <- props(f(parent_instance))
} |
Note that defining a method on a union is just a shortcut for defining a method for each class. Another way to solve this would be to define a separate method for each and then factor out the common part into an ordinary function. That feels a bit more future proof to me, because |
@t-kalinowski thanks for the help --- However, I'm not sure if using @lawremi's comment about heavy coupling echoes some of the feelings I am having while using FWIW, while I have been implementing binary operators, the two forms of method(op, list(A2, A2)) = \(x, y) {
# do some stuff, and then...
op(super(x, A2), super(y, A1))
} To me, |
Just realized in the non-union case what I think I'm looking for is In the case of unions it seems to me this would still be useful to have. However, at least this gives a path forward for me in the short term, as I should be able to write a simple wrapper around |
In case it's helpful, this solution seems to work for my cases (doesn't handle non-S7 classes but that's not a problem for my use case, and could be fixed): #' Get the single class in `to` (if it is a union) that is in the
#' class hierarchy of `from`
#' @noRd
as_single_ancestor = \(to, from) {
if (inherits(to, "S7_union")) {
is_ancestor = vapply(to$classes, S7_inherits, NA, x = from)
if (sum(is_ancestor) != 1) {
stop("Cannot dispatch on a class union unless object inherits from exactly one class in the union.")
}
to$classes[[which(is_ancestor)]]
} else {
to
}
}
#' Alternative to super() that supports unions
#' @param from object to dispatch on
#' @param to class or class union to use for dispatch --- if it is a union,
#' then there must be exactly one class in the union in the class hierarchy
#' of `from`
#' @noRd
dispatch = \(from, to) {
super(from, as_single_ancestor(to, from))
}
#' Alternative to super() that looks one class up
#' @param from object to dispatch on
#' @param to class or class union to use for dispatch --- if it is a union,
#' then there must be exactly one class in the union in the class hierarchy
#' of `from`. Dispatches on the parent to that class.
#' @noRd
parent = \(from, to) {
super(from, as_single_ancestor(to, from)@parent)
} Now for "dispatch on this specific class" I can use (Incidentally, splitting this into two different operations made me wonder if |
I'm not sure how to use
super()
when implementing a method for a class union. e.g.:I think I would have to implement
f()
twice, once forA_child
and once forB_child
(which feels like it defeats the purpose of class unions), or use a condition to pick the second argument tosuper()
based on the class ofx
(which feels clumsy).Is there a more elegant existing solution? If not, perhaps syntax like
f(super(x, A | B))
? To maintain the explicitness that motivatedsuper()
it could require there to be exactly one class in the intersection between theto
argument tosuper()
and the ancestors ofx
.(P.S. thanks for all of this, it is very fun to play with!)
The text was updated successfully, but these errors were encountered: