RConsortium / S7

S7: a new OO system for R
https://rconsortium.github.io/S7
Other
415 stars 38 forks source link

How to document S7 methods? #315

Open hadley opened 1 year ago

lawremi commented 1 year ago

For single dispatch methods, one could just follow the S3 conventions, right? And since double dispatch is just based on single dispatch, they could use the same approach for now?

hadley commented 1 year ago

It's not urgent to solve this problem because R CMD check currently isn't aware of S7 methods, so does not require that they be documented. But we do need to think about this longer term: do we want S7 to be like S3 where method documentation is optional or like S4 where it's required? Or do we want something new? (e.g. only require method documentation if the generic uses ... and the method has an argument that the generic does not).

We also need to think about the overall help experience. Do we expect to provide an ? experience like S4? (I think the only drawback is that it's potentially quite a bit of work for a function that relatively few users seem to know about; but we could certainly market it more). Or do we want to lean into dynamic documentation so that the generic would always list all the methods that are currently loaded (i.e. #167)? Either way, we'll need some way to declare in the Rd metadata that this is an S7 method — can we (ab)use existing Rd syntax to do so, or do we need something new? (We can certainly use \method() for single dispatch generics, but what about multi-dispatch?) Or can we get by with just a convention for aliases?

jeffkimbrel commented 1 year ago

Could a description or similar argument be added to the new_generic() and method() functions to hold a short text description that displays when the generic gets printed?

Looking at the S7 basics it currently has...

> describe
#> <S7_generic> describe(x, ...) with 3 methods:
#> 1: method(describe, pet)
#> 2: method(describe, dog)
#> 3: method(describe, S7_object)

But I could imagine having the text of the description argument returned somewhere...

method(describe, dog, description = "returns the name and age of the dog") <- function(x) {
    paste0(x@name, " is a ", x@age, " year old dog")
}

> describe
#> <S7_generic> describe(x, ...) with 3 methods:
#> 1: method(describe, pet)
#> 2: method(describe, dog) "returns the name and age of the dog" 
#> 3: method(describe, S7_object)

I'm just learning S7 and probably not qualified to comment yet, but I did find this github issue because one of the first tings I did was try ?describe to see if anything came up.

hadley commented 1 year ago

@jeffkimbrel I don't think think we want to move in the docstrings direction. IMO it's better to stick to existing .Rd conventions since we already have lots of tooling there.

lawremi commented 1 year ago

Agreed that it would be best to hold off on making docstrings a part of the API. Perhaps one day R will support formal annotations. Until then, I think we follow S4 by deciding on an alias convention that is eventually enforced by R CMD check. It would be cool if the alias actually evaluated to the method. For example, generic$class1$class2. The S7 package could provide its own utilities for linting the documentation until the merge with base. As an aside, it would be nice if the print method for generics and methods gave the recommended syntax for looking up their documentation.

hadley commented 1 year ago

Printing a generic currently shows you the syntax to call each of its methods; it will be easy to adapt that to show how to find docs instead/as well.

lawremi commented 1 month ago

Some more thoughts on this as I contemplate documenting a package:

Experience shows that users do not make use of the S4 facilities on ?(), such as method?my_generic(class, ...) or ?my_generic(x, ...). We never quite went the route of dynamic documentation, like listing all of the methods for a generic or class. It can be quite verbose, for example because some methods exist only for disambiguation, and class_any methods would show up everywhere.

In the end, we just documented the polymorphic behavior of generics in general terms, so that the user gained some intuition for the effect of calling a generic with a set of objects. It's more of an art than a science.

Checking for the presence of an alias is helpful, because it forces the developer to acknowledge that any new behavior has been folded into the documentation. Might as well use the S4 syntax for that.