Is it possible to simply the use of NULL slots (or at least improve the help files)?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Is it possible to simply the use of NULL slots (or at least improve the help files)?

aBBy Spurdle, ⍺XY
As far as I can tell, there's no trivial way to set arbitrary S4 slots to NULL.

Most of the online examples I can find, use setClassUnion and are
about 10 years old.
Which, in my opinion, is defective.
There's nothing "robust" about making something that should be
trivially simple, really complicated.

Maybe there is a simpler way, and I just haven't worked it out, yet.
But either way, could the documentation for the methods package be improved?
I can find any obvious info on NULL slots:

Introduction
Classes
Classes_Details
setClass
slot

Again, maybe I missed it.
Even setClassUnion, which is what's used in the online examples,
doesn't contain a NULL slot example.

One more thing:
The help file for setClassUnion, uses the term "superclass", incorrectly.

Its examples include the following:
setClassUnion("maybeNumber", c("numeric", "logical"))

If maybeNumber was the superclass of numeric, then every instance of
numeric would also be an instance of maybeNumber...

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Is it possible to simply the use of NULL slots (or at least improve the help files)?

aBBy Spurdle, ⍺XY
Sorry, the title should be "simplify", and the third paragraph should
say "I can't".
(Don't know how I missed these).

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Is it possible to simply the use of NULL slots (or at least improve the help files)?

Martin Morgan-4
In reply to this post by aBBy Spurdle, ⍺XY
I did ?"NULL<tab> at the command line and was lead to ?"NULL-class" and the BasicClasses help page in the methods package.

getClass("NULL"), getClass("character") show that these objects are unrelated, so a class union is the way to define a class that is the union of these. The essence of the behavior you would like is

  setClassUnion("character_OR_NULL", c("character", "NULL"))
  .A = setClass("A", slots = c(x = "character_OR_NULL"))

with

> .A(x = NULL)
An object of class "A"
Slot "x":
NULL

> .A(x = month.abb)
An object of class "A"
Slot "x":
 [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"

> .A(x = 1:5)
Error in validObject(.Object) :
  invalid class "A" object: invalid object for slot "x" in class "A": got class "integer", should be or extend class "character_OR_NULL"

I understand there are situations where NULL is desired, perhaps to indicate 'not yet initialized' and distinct from character(0) or NA_character_, but want to mention those often appropriate alternatives.

With

  setClassUnion("maybeNumber", c("numeric", "logical"))

every instance of numeric _is_ a maybeNumber, e.g.,

> is(1, "maybeNumber")
[1] TRUE
> is(1L, "maybeNumber")
[1] TRUE
> is(numeric(), "maybeNumber")
[1] TRUE
> is(NA_integer_, "maybeNumber")
[1] TRUE

which I think is consistent with the use of 'superclass' on the setClassUnion help page.

Martin Morgan
 

On 9/23/20, 5:20 PM, "R-devel on behalf of Abby Spurdle" <[hidden email] on behalf of [hidden email]> wrote:

    As far as I can tell, there's no trivial way to set arbitrary S4 slots to NULL.

    Most of the online examples I can find, use setClassUnion and are
    about 10 years old.
    Which, in my opinion, is defective.
    There's nothing "robust" about making something that should be
    trivially simple, really complicated.

    Maybe there is a simpler way, and I just haven't worked it out, yet.
    But either way, could the documentation for the methods package be improved?
    I can find any obvious info on NULL slots:

    Introduction
    Classes
    Classes_Details
    setClass
    slot

    Again, maybe I missed it.
    Even setClassUnion, which is what's used in the online examples,
    doesn't contain a NULL slot example.

    One more thing:
    The help file for setClassUnion, uses the term "superclass", incorrectly.

    Its examples include the following:
    setClassUnion("maybeNumber", c("numeric", "logical"))

    If maybeNumber was the superclass of numeric, then every instance of
    numeric would also be an instance of maybeNumber...

    ______________________________________________
    [hidden email] mailing list
    https://stat.ethz.ch/mailman/listinfo/r-devel
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Is it possible to simply the use of NULL slots (or at least improve the help files)?

aBBy Spurdle, ⍺XY
Hi Martin,
Thankyou for your response.

I suspect that we're not going to agree on the main point.
Making it trivially simple (as say Java) to set slots to NULL.
So, I'll move on to the other points here.

***Note that cited text uses excerpts only.***

>   setClassUnion("character_OR_NULL", c("character", "NULL"))
>   A = setClass("A", slots = c(x = "character_OR_NULL"))

I think the above construct needs to be documented much more clearly.
i.e. In the introductory and details pages for S4 classes.
This is something that many people will want to do.
And BasicClasses or NULL-class, are not the most obvious place to
start looking, either.

Also, I'd recommend the S4 authors, go one step further.
Include character_OR_NULL, numeric_OR_NULL, etc, or something similar,
in S4's predefined basic classes.
Otherwise, contributed packages will (eventually) end up with hundreds
of copies of these.

> setClassUnion("maybeNumber", c("numeric", "logical"))
> every instance of numeric _is_ a maybeNumber, e.g.,
> > is(1, "maybeNumber")
> [1] TRUE

> which I think is consistent with the use of 'superclass'

Not quite.

    x <- structure (sqrt (37), class = c ("sqrt.prime", "numeric") )
    is (x, "numeric") #TRUE
    is (x, "maybeNumber") #FALSE

So now, an object x, is a numeric but not a maybeNumber.
Perhaps a class union should be described as a partial imitation of a
superclass, for the purpose of making slots more flexible.


B.

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Is it possible to simply the use of NULL slots (or at least improve the help files)?

Martin Morgan-4
Answering to convey the 'rules' as I know them, rather than to address the underlying issues that I guess you are really after...

The S4 practice is to use setOldClass() to explicitly treat an S3 character() vector of classes as an assertion of linear inheritance

> x <- structure (sqrt (37), class = c ("sqrt.prime", "numeric") )
> is(x, "maybeNumber")
[1] FALSE
> setOldClass(class(x))
> is(x, "maybeNumber")
[1] TRUE

There are some quite amusing things that can go on with S3 classes, since the class attribute is just a character vector. So

> x <- structure ("September", class = c ("sqrt.prime", "numeric") )
> is(x, "numeric")  ## similarly, inherits()
[1] TRUE
> x <- structure (1, class = c ("numeric", "character"))
> is(x, "numeric")
[1] TRUE
> is(x, "character")
[1] TRUE

Perhaps the looseness of the S3 system motivated the use of setOldClass() for anything more than assertion of simple relationships? At least in this context setOldClass() provides some type checking sanity

> setOldClass(c("character", "numeric"))
Error in setOldClass(c("character", "numeric")) :
  inconsistent old-style class information for "character"; the class is defined but does not extend "numeric" and is not valid as the data part
In addition: Warning message:
In .validDataPartClass(cl, where, dataPartClass) :
  more than one possible class for the data part: using "numeric" rather than "character"

Martin Morgan

On 9/24/20, 4:51 PM, "Abby Spurdle" <[hidden email]> wrote:

    Hi Martin,
    Thankyou for your response.

    I suspect that we're not going to agree on the main point.
    Making it trivially simple (as say Java) to set slots to NULL.
    So, I'll move on to the other points here.

    ***Note that cited text uses excerpts only.***

    >   setClassUnion("character_OR_NULL", c("character", "NULL"))
    >   A = setClass("A", slots = c(x = "character_OR_NULL"))

    I think the above construct needs to be documented much more clearly.
    i.e. In the introductory and details pages for S4 classes.
    This is something that many people will want to do.
    And BasicClasses or NULL-class, are not the most obvious place to
    start looking, either.

    Also, I'd recommend the S4 authors, go one step further.
    Include character_OR_NULL, numeric_OR_NULL, etc, or something similar,
    in S4's predefined basic classes.
    Otherwise, contributed packages will (eventually) end up with hundreds
    of copies of these.

    > setClassUnion("maybeNumber", c("numeric", "logical"))
    > every instance of numeric _is_ a maybeNumber, e.g.,
    > > is(1, "maybeNumber")
    > [1] TRUE

    > which I think is consistent with the use of 'superclass'

    Not quite.

        x <- structure (sqrt (37), class = c ("sqrt.prime", "numeric") )
        is (x, "numeric") #TRUE
        is (x, "maybeNumber") #FALSE

    So now, an object x, is a numeric but not a maybeNumber.
    Perhaps a class union should be described as a partial imitation of a
    superclass, for the purpose of making slots more flexible.


    B.
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Bob
Reply | Threaded
Open this post in threaded view
|

Re: Is it possible to simply the use of NULL slots (or at least improve the help files)?

Bob
It seems one of the primary reasons to use the S4 system is *to be strict
about types.*

IMO the documentation is quite clear on this point, if NULL is not a
subclass of character, which it isn't because inherits(NULL, "character")
is FALSE then everything is behaving exactly as expected and documented.

Between making the calling function responsible for passing an object of
the correct type and setClassUnion, it doesn't seem that complicated to
handle the use case.

On Thu, Sep 24, 2020 at 5:26 PM Martin Morgan <[hidden email]>
wrote:

> Answering to convey the 'rules' as I know them, rather than to address the
> underlying issues that I guess you are really after...
>
> The S4 practice is to use setOldClass() to explicitly treat an S3
> character() vector of classes as an assertion of linear inheritance
>
> > x <- structure (sqrt (37), class = c ("sqrt.prime", "numeric") )
> > is(x, "maybeNumber")
> [1] FALSE
> > setOldClass(class(x))
> > is(x, "maybeNumber")
> [1] TRUE
>
> There are some quite amusing things that can go on with S3 classes, since
> the class attribute is just a character vector. So
>
> > x <- structure ("September", class = c ("sqrt.prime", "numeric") )
> > is(x, "numeric")  ## similarly, inherits()
> [1] TRUE
> > x <- structure (1, class = c ("numeric", "character"))
> > is(x, "numeric")
> [1] TRUE
> > is(x, "character")
> [1] TRUE
>
> Perhaps the looseness of the S3 system motivated the use of setOldClass()
> for anything more than assertion of simple relationships? At least in this
> context setOldClass() provides some type checking sanity
>
> > setOldClass(c("character", "numeric"))
> Error in setOldClass(c("character", "numeric")) :
>   inconsistent old-style class information for "character"; the class is
> defined but does not extend "numeric" and is not valid as the data part
> In addition: Warning message:
> In .validDataPartClass(cl, where, dataPartClass) :
>   more than one possible class for the data part: using "numeric" rather
> than "character"
>
> Martin Morgan
>
> On 9/24/20, 4:51 PM, "Abby Spurdle" <[hidden email]> wrote:
>
>     Hi Martin,
>     Thankyou for your response.
>
>     I suspect that we're not going to agree on the main point.
>     Making it trivially simple (as say Java) to set slots to NULL.
>     So, I'll move on to the other points here.
>
>     ***Note that cited text uses excerpts only.***
>
>     >   setClassUnion("character_OR_NULL", c("character", "NULL"))
>     >   A = setClass("A", slots = c(x = "character_OR_NULL"))
>
>     I think the above construct needs to be documented much more clearly.
>     i.e. In the introductory and details pages for S4 classes.
>     This is something that many people will want to do.
>     And BasicClasses or NULL-class, are not the most obvious place to
>     start looking, either.
>
>     Also, I'd recommend the S4 authors, go one step further.
>     Include character_OR_NULL, numeric_OR_NULL, etc, or something similar,
>     in S4's predefined basic classes.
>     Otherwise, contributed packages will (eventually) end up with hundreds
>     of copies of these.
>
>     > setClassUnion("maybeNumber", c("numeric", "logical"))
>     > every instance of numeric _is_ a maybeNumber, e.g.,
>     > > is(1, "maybeNumber")
>     > [1] TRUE
>
>     > which I think is consistent with the use of 'superclass'
>
>     Not quite.
>
>         x <- structure (sqrt (37), class = c ("sqrt.prime", "numeric") )
>         is (x, "numeric") #TRUE
>         is (x, "maybeNumber") #FALSE
>
>     So now, an object x, is a numeric but not a maybeNumber.
>     Perhaps a class union should be described as a partial imitation of a
>     superclass, for the purpose of making slots more flexible.
>
>
>     B.
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel