[Rd] "Math" group generics for S4, and a bug

Martin Maechler maechler at stat.math.ethz.ch
Tue Jun 26 22:28:38 CEST 2007

>>>>> "JMC" == John Chambers <jmc at r-project.org>
>>>>>     on Tue, 26 Jun 2007 14:47:25 -0400 writes:

    JMC> Martin Maechler wrote:
    >>>>>>> "MM" == Martin Maechler <maechler at stat.math.ethz.ch>
    >>>>>>> on Sat, 23 Jun 2007 00:36:43 +0200 writes:
> {on R-help}
    >> [.....................]  [.....................]
    >> >> Duncan Murdoch
    DM> You might have better luck with
    DM> log1p(tasa)
    MM> {very good point, thank you, Duncan!}
    DM> if the authors of the Matrix package have written a
    DM> method for log1p(); if not, you'll probably have to do
    DM> it yourself.
    MM> They have not yet.
    MM> Note however that this - and expm1() - would
    MM> automagically work for sparse matrices if these two
    MM> functions were part of the "Math" S4 group generic.
    MM> I'd say that there's only historical reason for them
    MM> *not* to be part of "Math", and I am likely going to
    MM> propose to change this ....
    >> I'm now going to propose ...
    >> As I found, expm1() and log1p() already *HAVE BEEN* in
    >> the S3 "Math" group generic ``automagically by
    >> implementation''.  Just the documentation for this fact
    >> has been missing.
    >> Hence, I've added that doc (uncommitted) and I'm about to
    >> add them to the S4 Math group as well.  When doing so,
    >> I'd like to add few more functions to make S3 and S4
    >> "Math" a bit more compatible : Consequently, I'm
    >> proposing to add the following functions to the S4 Math
    >> group generic :
    >> - log1p, expm1
    >> - cummax, cummin {S3 has them; cumprod(), cumsum() are
    >> already}
    >> - digamma, trigamma {S3 has them; gamma(), lgamma() are
    >> already}
    >> ----
    >> When trying to do the above, I'm pretty quickly
    >> successful for cummax & cummin, most probably because
    >> they are primitive functions.  But I currently have
    >> problems for the other four, and in exploring these
    >> problems, I've found that
    >> log10()
    >> does not S4- dispatch on "Math" neither, which I think is
    >> a pretty peculiar bug;

    JMC> Well, it depends what you mean by "bug"; I would call
    JMC> it a "design infelicity" (a la Bill Venables), and some
    JMC> might call it a failure to Do What I Mean.  Assuming I
    JMC> understand what you meant (you didn't give an example)
    JMC> I disagree with the letter but very much agree with the
    JMC> spirit.

    JMC> In fact, log10 _is_ in the Math group.  But the
    JMC> programmer is currently responsible for creating a
    JMC> suitable generic function (that's the design
    JMC> infelicity).  If that is done correctly, dispatch seems
    JMC> to work fine:

    >> setGeneric("log10", group = "Math")
    JMC> [1] "log10"

yes, indeed.  Embarrassingly, actually I did know about this,
and indeed, it's not a bug.

    >> setClass("onX", representation(x="numeric", stuff =
    >> "character"))
    JMC> [1] "onX"
    >> setMethod("Math", "onX", function(x)callGeneric(x at x))
    JMC> [1] "Math"
    >> xx = new("onX", x=1:10, stuff = "test") log10(xx)
    JMC>  [1] 0.0000000 0.3010300 0.4771213 0.6020600 0.6989700
    JMC> 0.7781513 0.8450980 [8] 0.9030900 0.9542425 1.0000000
    >> showMethods("log10")
    JMC> Function: log10 (package base) x="ANY" x="integer"
    JMC> (inherited from: x="ANY") x="onX" (definition from
    JMC> function "Math")

    JMC> So unless you mean something different by "does not S4-
    JMC> dispatch", this is not technically a bug.  Your bug
    JMC> presumably came when you either did not call
    JMC> setGeneric() on log10() or else called it in the simple
    JMC> setGeneric("log10") form.

you are right.

    JMC> But in principle I very much agree that this is not a
    JMC> satisfactory situation.  It should be implicit in the
    JMC> definition of log10() that when it is made a generic,
    JMC> that generic has group "Math".  The reason it must now
    JMC> be done by the programmer is that log10() is not a
    JMC> primitive, and so not covered by the automatic
    JMC> definition of a generic that, e.g., applies to sin().

    JMC> I have a proposal to fix this, by generalizing the
    JMC> mechanism used for primitives in base, so that it would
    JMC> allow any function in any package to have an implicit
    JMC> generic form.  When a method is specified for the
    JMC> function, the implicit generic becomes the actual
    JMC> function.

That sounds like a very good idea, allowing the function writer
to specify (if and) how the function should behave as generic.

    JMC>   Sometime after 2.5.1 comes out, this should
    JMC> with luck find its way to r-devel so we can see if it
    JMC> helps.

So, I'm hoping for good luck.. ;-) :-)

Thanks a lot, John!

    >> I think if that was fixed, then my code changes would
    >> also work to make log1p(), expm1(), digamma() and
    >> trigamma() correctly part of "S4 - Math Group".
    >> Martin

More information about the R-devel mailing list