

Hi,
i have used S4 classes to implement a unified access to random number generators
(package rstream on CRAN).
I have used a construct to allow optional arguments:
if(!isGeneric("rstream.sample"))
setGeneric("rstream.sample", function(stream,...) standardGeneric("rstream.sample"))
setMethod("rstream.sample", c("rstream","numeric"),
function(stream,n=1) { ... [ code ] ... } )
Thus if rs is an instance of an rstream object one can a random
sample of size 10 using
rstream.sample(rs, 10)
for a sample of size 1 one can use equivalently
rstream.sample(rs,1)
rstream.sample(rs)
however, with Rdevel the above construct does not work any more, due to
more stringent checkings. It can be fixed by replacing it by
if(!isGeneric("rstream.sample"))
setGeneric("rstream.sample", function(stream,n) standardGeneric("rstream.sample"))
setMethod("rstream.sample", c("rstream","numeric"),
function(stream,n=1) { ... [ code ] ... } )
then rstream.sample(rs) does not work any more.
Is there still a way to allow optional arguments for methods of
S4 classes?
Josef
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Hi Josef,
On 14 Feb 2006, [hidden email] wrote:
> I have used a construct to allow optional arguments:
>
> if(!isGeneric("rstream.sample")) setGeneric("rstream.sample",
> function(stream,...) standardGeneric("rstream.sample"))
First, a question:
Is this idiom of testing for the generic before defining it still
"recommended"? It seems to me that one should either define one's
own generic in the package namespace or define a method for a
*particular* generic defined elsewhere. Otherwise, one could end up
defining a method for the wrong generic.
> setMethod("rstream.sample", c("rstream","numeric"),
> function(stream,n=1) { ... [ code ] ... } )
This will work if you remove the second arg in the signature. That
is,
setMethod("rstream.sample", signature(stream="rstream"),
function(strea, n=1) { ... })
Putting an arg in the signature means dispatching on that arg. You
cannot dispatch on an arg that is not named in the definition of the
generic.
> however, with Rdevel the above construct does not work any more,
> due to more stringent checkings. It can be fixed by replacing it by
>
> if(!isGeneric("rstream.sample")) setGeneric("rstream.sample",
> function(stream,n) standardGeneric("rstream.sample"))
>
> setMethod("rstream.sample", c("rstream","numeric"),
> function(stream,n=1) { ... [ code ] ... } )
>
> then rstream.sample(rs) does not work any more.
>
> Is there still a way to allow optional arguments for methods of S4
> classes?
Here's an approach that works for me:
1. You have to specify a default value to args *in the generic*. This
doesn't make a whole lot of sense to me, but it does seem to be
needed.
setGeneric("rstream.sample",
function(stream, n=0) standardGeneric("rstream.sample"))
2. Then define a method with a signature that matches the default
case:
setMethod("rstream.sample", signature(stream="rstream", n="missing"),
function(stream, n=1) { ... })
Note that you could also use signature(stream="rstream"), but then
a call like rstream.sample(s, "foo") could match... Leaving out the
arg is like saying n="ANY".
HTH,
+ seth
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


The problem is not the optional argument, but the attempt to dispatch on
an argument not in the generic.
setGeneric("rstream.sample", function(stream, ...)
standardGeneric("rstream.sample"))
setMethod("rstream.sample", "rstream", function(stream,n=1) { print(n) } )
rstream.sample(rs, 10)
[1] 10
rstream.sample(rs)
[1] 1
works, and seems to work as you intended.
On Tue, 14 Feb 2006, Josef Leydold wrote:
> Hi,
>
> i have used S4 classes to implement a unified access to random number generators
> (package rstream on CRAN).
>
> I have used a construct to allow optional arguments:
>
> if(!isGeneric("rstream.sample"))
> setGeneric("rstream.sample", function(stream,...) standardGeneric("rstream.sample"))
>
> setMethod("rstream.sample", c("rstream","numeric"),
> function(stream,n=1) { ... [ code ] ... } )
>
> Thus if rs is an instance of an rstream object one can a random
> sample of size 10 using
>
> rstream.sample(rs, 10)
>
> for a sample of size 1 one can use equivalently
>
> rstream.sample(rs,1)
> rstream.sample(rs)
>
> however, with Rdevel the above construct does not work any more, due to
> more stringent checkings. It can be fixed by replacing it by
>
> if(!isGeneric("rstream.sample"))
> setGeneric("rstream.sample", function(stream,n) standardGeneric("rstream.sample"))
>
> setMethod("rstream.sample", c("rstream","numeric"),
> function(stream,n=1) { ... [ code ] ... } )
>
> then rstream.sample(rs) does not work any more.
>
> Is there still a way to allow optional arguments for methods of
> S4 classes?
>
> Josef
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel>
>

Brian D. Ripley, [hidden email]
Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/University of Oxford, Tel: +44 1865 272861 (self)
1 South Parks Road, +44 1865 272866 (PA)
Oxford OX1 3TG, UK Fax: +44 1865 272595
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Echoing similar suggestions, but with a bit of philosophy... How about:
setGeneric("rstream.sample",
function( stream, ... ) standardGeneric("rstream.sample"))
setMethod("rstream.sample", c( "numeric" ),
function( stream, n = 1, ... ) { code } )
It seems to me like the generic should (always?) just have arguments
used for dispatch  stream, in this case  and that methods then
specify default values. To also dispatch on the second argument, one
might
setGeneric("rstream.sample",
function( stream, n, ... ) standardGeneric("rstream.sample"))
setMethod("rstream.sample", c( "rstream.sample", "numeric" ),
function( stream, n, ... ) { code } )
setMethod("rstream.sample", c( "rstream.sample", "missing" ),
function( stream, n, ... ) rstream.sample( stream, n = 1 ))
setMethod("rstream.sample", c( "rstream.sample", "otherclass" ),
function( stream, n, ... ) n )
Martin
"Josef Leydold" < [hidden email]> writes:
> Hi,
>
> i have used S4 classes to implement a unified access to random number generators
> (package rstream on CRAN).
>
> I have used a construct to allow optional arguments:
>
> if(!isGeneric("rstream.sample"))
> setGeneric("rstream.sample", function(stream,...) standardGeneric("rstream.sample"))
>
> setMethod("rstream.sample", c("rstream","numeric"),
> function(stream,n=1) { ... [ code ] ... } )
>
> Thus if rs is an instance of an rstream object one can a random
> sample of size 10 using
>
> rstream.sample(rs, 10)
>
> for a sample of size 1 one can use equivalently
>
> rstream.sample(rs,1)
> rstream.sample(rs)
>
> however, with Rdevel the above construct does not work any more, due to
> more stringent checkings. It can be fixed by replacing it by
>
> if(!isGeneric("rstream.sample"))
> setGeneric("rstream.sample", function(stream,n) standardGeneric("rstream.sample"))
>
> setMethod("rstream.sample", c("rstream","numeric"),
> function(stream,n=1) { ... [ code ] ... } )
>
> then rstream.sample(rs) does not work any more.
>
> Is there still a way to allow optional arguments for methods of
> S4 classes?
>
> Josef
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


On 14 Feb 2006, [hidden email] wrote:
> It seems to me like the generic should (always?) just have arguments
> used for dispatch  stream, in this case  and that methods then
> specify default values.
There are advantages to adding named arguments to a generic to define
the expected interface. These 'extra' args may not be *needed* for
dispatch in the sense that the first arg may be enough to decide what
method you want.
So IMO, there are two reasons to put an arg in a generic:
1. You really want to dispatch on it.
2. You want to define an interface and can handle the fact that you
will have to also dispatch on it.
I guess my point is that for downstream developers extending your
generic and for the sake of documentation, relying too much on '...'
can make things difficult.
> To also dispatch on the second argument, one
> might
>
> setGeneric("rstream.sample",
> function( stream, n, ... ) standardGeneric("rstream.sample"))
>
> setMethod("rstream.sample", c( "rstream.sample", "numeric" ),
> function( stream, n, ... ) { code } )
>
> setMethod("rstream.sample", c( "rstream.sample", "missing" ),
> function( stream, n, ... ) rstream.sample( stream, n = 1 ))
And here I might offer a slight improvement. Putting the default
value in the signature of the function will give automated tools a
chance to document:
setMethod("rstream.sample", c("rstream.sample", "missing"),
function( stream, n=1, ...) rstream.sample(stream, n))
+ seth
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel

