[Roxygen-devel] S4 implementation of @usage

Vitalie Spinu spinuvit at gmail.com
Wed Aug 29 19:00:50 CEST 2012


  >> Hadley Wickham <hadley at rice.edu>
  >> on Wed, 29 Aug 2012 09:07:41 -0500 wrote:

  > Hi Vitalie,
  > It would also be really useful if you could sketch out the S4 design
  > to work with a tag like usage.

  > Would you need multiple dispatch so that usage looks like:

  > setMethod("ProcessTag", signature(tag = "RoccerUsage", object =
  > "function"), ...)
  > setMethod("ProcessTag", signature(tag = "RoccerUsage", object =
  > "classRepresentation"), ...)
  > setMethod("ProcessTag", signature(tag = "RoccerUsage", object =
  > "MethodDefinition"), ...)

Yes, this is precisely what I had in mind. A couple of comments.

 1)  Its a convention in R that class names are CamelCase (as you did) but
 method names are CamelCase which start with small letter (processTag). 
 
 It's a very nice convention, especially with
 functions_separated_by_underscors conventions which you extensively
 use. Code becomes very easy to read, as you know what is method, class
 and where is a simple function or object. 

 2) I think processTag should have 4 arguments (though I might be not
 seeing the whole picture). The third argument being RocBlock (or RocDoc?) -- an
 object containing all the tags of the current documentation chunk and
 an object. The forth being RocPackage containing all the RocDoc objects
 collected during the evaluation. The processTag method for a specific
 tag need not use the last two. RocBlock is needed, because the tag
 processing might depend on other tags in the same documentation chunk.

 No need to dispatch on the last 2 arguments as far. May be in the
 future when you will have different types of RocBlocks and RocPackage
 (oxigen, markdown etc.).

 The question is how you make tags "communicate" to each other (global
 tags like family or inheritParams). One option is preParse stage (which
 I think you are doing right now). Another one, is to add one special
 slot to global tags which is a common environment. Then this special
 tags can communicate to each other using that environment.

  > Is that better than this? (effectively the same as the current s3
  > implementation)

  > setMethod("ProccessTag", signature(tag = "RoccerUsage"), function(tag, obj) {
  >   makeUsageObject(obj at value, obj at name)
  > }
  > setMethod("makeUsageObject", signature(object = "function"), ...)
  > setMethod("makeUsageObject", signature(object = "classRepresentation"), ...)
  > setMethod("makeUsageObject", signature(object = "MethodDefinition"), ...)

This is no good, for each Tag you create a method. The main thing about
methods is that you can have one processTag and that works for all tags.

  > Currently the roccer implements the strategy design pattern so that
  > you can separately specify the parser and the output. How would you do
  > the same with S4?  Multiple inheritance?

This are methods for each tag. You must have rocParse method and rocRd
method, that's all. Not rocOut, you will pretty soon have rocHTHL,
rocMarkdown etc to output into other formats. (maybe outputRd,
outputHTML etc).

  > setClass("RoccerUsage", contains = c("RoccerParseSingle",
  > "RoccerOutRd"))

This is not good. Tag class is an entity to represent an abstract and
isolated notion of a tag concept. It should not have anything to do with
the output output, parsing, printing etc. All of the actions which one
might apply to an object should be implemented as methods. I guess you
are still thinking in C++ way of classes comprising objects structure
and methods in one entity.  In S4 they are completely separated.

  > setMethod("ProcessTag", signature(tag = "RoccerUsage"), function(tag, roc) ...)
  > setMethod("OutRd", signature(tag = "RoccerUsage"), function(tag) ...)

Ah ... ok, reading it now :) Somehow I missed this on the first skim.
Sure, this is the way!

  > setClass("RoccerUsage", contains = "Roccer")
  > setMethod("Process", signature(tag = "RoccerUsage"), function(tag,
  > rocblocks) ...)
  > setMethod("Output", signature(tag = "RoccerUsage"), function(tag,
  > rocblocks) ...)

But wait a second. Why do you need Roccers? What is roccer? You have tag
classes representing the tags. 

I will write a rough sketch of the system in a separate mail.

        Vitalie


More information about the Roxygen-devel mailing list