[R-pkg-devel] Extending/adding to an R6 class from another package: qns
hongooi @ending from micro@oft@com
Fri Oct 19 18:27:03 CEST 2018
I do use subclassing as you suggest. In my base package I have an az_resource class that represents any generic Azure resource. Eg in the VM package, I extend it to obtain az_vm_resource; in the storage package I extend it to obtain az_storage; and so on. In addition to simple subclassing, I also define more complex classes that combine resources of different types.
However, Azure also has a hierarchical structure where a subscription can contain multiple resource groups, each of which can contain multiple resources. So I have a resource_group class that includes functions to manage resources. It's this class that I'm adding methods to at runtime, so that you can work with az_vm_resource objects the same way that you work with az_resource objects.
Given that I'm using R6 (for its persistent state, since I'm tracking Azure resources), and given that I'm writing multiple packages, I don't really see any way around "monkey-patching" classes on load. Azure has approximately 1e6 services on offer, and I don't want to support them via one monster package (in principle).
You can see the work-in-progress on the CloudyR repo if you like:
In any case, I've realised I can work around the note about startup messages by simply hiving off all the xxx$set() calls to a secondary function, rather than having them directly in .onLoad().
From: Hadley Wickham <h.wickham using gmail.com>
Sent: Saturday, 20 October, 2018 2:42 AM
To: Hong Ooi <hongooi using microsoft.com>
Cc: R Package Development <r-package-devel using r-project.org>
Subject: Re: [R-pkg-devel] Extending/adding to an R6 class from another package: qns
I think monkey-patching classes on load is an extremely bad idea. You
would be better off subclassing, or if the classes are so closely
inter-related, you should put them in a single package. Or re-design
your interface to use the pipe instead of method chaining so this
isn't a problem (brief discussion at
> The reason for the warning is because writing documentation for R6 methods is rather awkward, even/especially with Roxygen. This goes doubly so when the method in question is for a class from a different package. What I've done is to write a Roxygen block for the method as if it was a standalone function; for example, the documentation for az_resource_group$get_vm() is like this:
> #' Get existing virtual machine(s)
> #' Method for the [AzureRMR::az_subscription] and [AzureRMR::az_resource_group] classes.
> #' @rdname get_vm
> #' @name get_vm
> #' @usage
> #' get_vm(name)
> #' get_vm(name, resource_group = name)
> #' @param name The name of the VM or cluster.
> #' @param resource_group For the `az_subscription` method, the resource group in which `get_vm()` will look for the VM. Defaults to the VM name.
> #' @details
> #' ...
> This way, typing ?get_vm will bring up the relevant page, which seems to me to be the best compromise in terms of the end-user experience. Is this an acceptable way of doing the documentation for CRAN?
I think the usage should be consistent with how people actually call
the function, i.e. x$get_vm(name). I'm not sure if R CMD check will
like this, but I suspect it will silence the warning.
More information about the R-package-devel