Skip to content

[R-pkg-devel] match.arg With S4 Methods and Missing Inputs

5 messages · Dario Strbenac, Andrew Simmons, Martin Maechler +1 more

#
Good day,

How can a parameter take a default value from a vector of permitted ones, if it is missing?

setClassUnion("characterOrMissing", c("character", "missing"))
setClassUnion("integerOrMissing", c("integer", "missing"))
setClass("SetOfParams", representation(A = "characterOrMissing", B = "integer"))
setGeneric("SetOfParams", function(A, B) standardGeneric("SetOfParams"))

setMethod("SetOfParams", c("missing", "missing"), function() # Empty constructor
{
  new("SetOfParams", A = "M", B = 100L)
})

setMethod("SetOfParams", c("characterOrMissing", "integerOrMissing"), function(A = c("L", "M", "N"), B = 100L)
{
  A <- match.arg(A)
  new("SetOfParams", A = A, B = B)
})

SetOfParams(B = 500L)
  Error in match.arg(A) : argument "A" is missing, with no default.

How can I avoid the error about A having no default? I thought I specified it so that it does have one, which match.arg would set for me if the user did not specify one.

--------------------------------------
Dario Strbenac
University of Sydney
Camperdown NSW 2050
Australia
#
always have default values of R_MissingArg
Providing default values within the methods does nothing since A and B have
already been initialized before arriving at the method.
You could do something like:


if (missing(A))
    A <- ...
if (missing(B))
    B <- ...


within each method, and that would emulate having default values for A and
B.

On Mon, Nov 8, 2021 at 12:00 AM Dario Strbenac <dstr7320 at uni.sydney.edu.au>
wrote:

  
  
#
You need to define  the generic with a default value for this parameter. Methods can then have a different default value for it. I remember reading this in S4's documentation but don't remember where.

Georgi Boshnakov

Get Outlook for Android<https://aka.ms/AAb9ysg>
#
> You need to define the generic with a default value for
    > this parameter. Methods can then have a different default
    > value for it. 
    > I remember reading this in S4's documentation but don't remember where.

    > Georgi Boshnakov

interesting ... and would make quite some sense.

Can others confirm / disprove ?

Even as co-author of the "using S4 almost everywhere" package 'Matrix'
I wouldn't have known this.

If this is seen to be true (I don't have time for checking just now),
I think it's something we really *should* add to one or more of
the related help pages.

Martin Maechler


    > ________________________________

    > Sent: Monday, November 8, 2021 5:37:18 AM
    > To: Dario Strbenac <dstr7320 at uni.sydney.edu.au>
    > Cc: r-package-devel at r-project.org <r-package-devel at r-project.org>
    > Subject: Re: [R-pkg-devel] match.arg With S4 Methods and Missing Inputs

    >> From the line `function(A, B) standardGeneric("SetOfParams")`, A and B will
    > always have default values of R_MissingArg
    > Providing default values within the methods does nothing since A and B have
    > already been initialized before arriving at the method.
    > You could do something like:


    > if (missing(A))
    > A <- ...
    > if (missing(B))
    > B <- ...


    > within each method, and that would emulate having default values for A and
    > B.

    > On Mon, Nov 8, 2021 at 12:00 AM Dario Strbenac <dstr7320 at uni.sydney.edu.au>
> wrote:
>> Good day,
    >> 
    >> How can a parameter take a default value from a vector of permitted ones,
    >> if it is missing?
    >> 
    >> setClassUnion("characterOrMissing", c("character", "missing"))
    >> setClassUnion("integerOrMissing", c("integer", "missing"))
    >> setClass("SetOfParams", representation(A = "characterOrMissing", B =
    >> "integer"))
    >> setGeneric("SetOfParams", function(A, B) standardGeneric("SetOfParams"))
    >> 
    >> setMethod("SetOfParams", c("missing", "missing"), function() # Empty constructor
    >> {
    >> new("SetOfParams", A = "M", B = 100L)
    >> })
    >> 
    >> setMethod("SetOfParams", c("characterOrMissing", "integerOrMissing"),
    >> function(A = c("L", "M", "N"), B = 100L)
    >> {
    >> A <- match.arg(A)
    >> new("SetOfParams", A = A, B = B)
    >> })
    >> 
    >> SetOfParams(B = 500L)
    >> Error in match.arg(A) : argument "A" is missing, with no default.
    >> 
    >> How can I avoid the error about A having no default? I thought I specified
    >> it so that it does have one, which match.arg would set for me if the user
    >> did not specify one.
    >> 
    >> --------------------------------------
    >> Dario Strbenac
    >> University of Sydney
    >> Camperdown NSW 2050
    >> Australia
    >> ______________________________________________
    >> R-package-devel at r-project.org mailing list
#
It turns out that it is not difficult to find, the excerpt below is from help(setMethod). Maybe  mentioning this in help(setGeneric) would be helpful, as well.

Georgi Boshnakov


=======
Method definitions can have default expressions for arguments, but
     only if the generic function must have _some_ default expression
     for the same argument. (This restriction is imposed by the way R
     manages formal arguments.)  If so, and if the corresponding
     argument is missing in the call to the generic function, the
     default expression in the method is used.  If the method
     definition has no default for the argument, then the expression
     supplied in the definition of the generic function itself is used,
     but note that this expression will be evaluated using the
     enclosing environment of the method, not of the generic function.
     Method selection does not evaluate default expressions.  All
     actual (non-missing) arguments in the signature of the generic
     function will be evaluated when a method is selected-when the call
     to 'standardGeneric(f)' occurs.  Note that specifying class
     '"missing"' in the signature does not require any default
     expressions.

-----Original Message-----
From: Martin Maechler <maechler at stat.math.ethz.ch> 
Sent: 08 November 2021 15:44
To: Georgi Boshnakov <georgi.boshnakov at manchester.ac.uk>
Cc: Andrew Simmons <akwsimmo at gmail.com>; Dario Strbenac <dstr7320 at uni.sydney.edu.au>; r-package-devel at r-project.org
Subject: Re: [R-pkg-devel] match.arg With S4 Methods and Missing Inputs
> You need to define the generic with a default value for
    > this parameter. Methods can then have a different default
    > value for it. 
    > I remember reading this in S4's documentation but don't remember where.

    > Georgi Boshnakov

interesting ... and would make quite some sense.

Can others confirm / disprove ?

Even as co-author of the "using S4 almost everywhere" package 'Matrix'
I wouldn't have known this.

If this is seen to be true (I don't have time for checking just now), I think it's something we really *should* add to one or more of the related help pages.

Martin Maechler


    > ________________________________

    > Sent: Monday, November 8, 2021 5:37:18 AM
    > To: Dario Strbenac <dstr7320 at uni.sydney.edu.au>
    > Cc: r-package-devel at r-project.org <r-package-devel at r-project.org>
    > Subject: Re: [R-pkg-devel] match.arg With S4 Methods and Missing Inputs

    >> From the line `function(A, B) standardGeneric("SetOfParams")`, A and B will
    > always have default values of R_MissingArg
    > Providing default values within the methods does nothing since A and B have
    > already been initialized before arriving at the method.
    > You could do something like:


    > if (missing(A))
    > A <- ...
    > if (missing(B))
    > B <- ...


    > within each method, and that would emulate having default values for A and
    > B.

    > On Mon, Nov 8, 2021 at 12:00 AM Dario Strbenac <dstr7320 at uni.sydney.edu.au>
> wrote:
>> Good day,
    >> 
    >> How can a parameter take a default value from a vector of permitted ones,
    >> if it is missing?
    >> 
    >> setClassUnion("characterOrMissing", c("character", "missing"))
    >> setClassUnion("integerOrMissing", c("integer", "missing"))
    >> setClass("SetOfParams", representation(A = "characterOrMissing", B =
    >> "integer"))
    >> setGeneric("SetOfParams", function(A, B) standardGeneric("SetOfParams"))
    >> 
    >> setMethod("SetOfParams", c("missing", "missing"), function() # Empty constructor
    >> {
    >> new("SetOfParams", A = "M", B = 100L)
    >> })
    >> 
    >> setMethod("SetOfParams", c("characterOrMissing", "integerOrMissing"),
    >> function(A = c("L", "M", "N"), B = 100L)
    >> {
    >> A <- match.arg(A)
    >> new("SetOfParams", A = A, B = B)
    >> })
    >> 
    >> SetOfParams(B = 500L)
    >> Error in match.arg(A) : argument "A" is missing, with no default.
    >> 
    >> How can I avoid the error about A having no default? I thought I specified
    >> it so that it does have one, which match.arg would set for me if the user
    >> did not specify one.
    >> 
    >> --------------------------------------
    >> Dario Strbenac
    >> University of Sydney
    >> Camperdown NSW 2050
    >> Australia
    >> ______________________________________________
    >> R-package-devel at r-project.org mailing list