Bug in str or issue with class management in my package?

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Bug in str or issue with class management in my package?

Ulrike Groemping
Dear developeRs,

with R 2.4.1 (and also 2.4.0), the function str() fails on objects of class relimplmbooteval, if there are unused slots, which is very often the case. I am not sure whether this is a bug in str() or a correct behavior of str() that unmasks some sloppiness in my usage of S4 classes (that I am not aware of)?

Reproducible example (package relaimpo needed):

The program

require(relaimpo)
bte<-booteval.relimp(boot.relimp(swiss,b=100))
str(bte)

yields the error message

Errorr in FUN(c("lmg.lower", "lmg.upper", "lmg.rank.lower", "lmg.rank.upper",  :
        no slot named "pmvd.lower" for this object of class "relimplmbooteval"
(back-translated from German).

Regards, Ulrike
Reply | Threaded
Open this post in threaded view
|

Re: Bug in str or issue with class management in my package?

Martin Morgan
Ulrike,

booteval.relimp has the statement

    ausgabe <- calc.relimp(empcov, type = type, diff = diff,
        rank = rank, rela = rela, always = always, groups = groups,
        groupnames = groupnames)
    class(ausgabe) <- "relimplmbooteval"

This changes the name of the class of ausgabe, without changing its
structure. I'm guessing that prior to this call ausgabe did not have a
slot "pmvd.lower". Here's the simpler version:

>setClass("A", representation=representation(x="numeric"))
[1] "A"
> setClass("B", contains="A", representation=representation(y="numeric"))
[1] "B"
> a <- new("A")
> class(a) <- "B"
> str(a)
Error in FUN(c("y", "x")[[1L]], ...) : no slot of name "y" for this object of class "B"

and some behavior which is somehow weird:

> slot(a, "y")
Error in slot(a, "y") : no slot of name "y" for this object of class "B"
> slot(a, "y") <- 10 # 'creates' the slot!
> slot(a, "y")
[1] 10

Probably what you want to do is to create a 'setAs' method

setAs('relimplm', 'relimplmbooteval',
      function(from) {
          <your code here, e.g.,>
      })

and use

    ausgabe <- as(ausgabe, "relimplmbooteval")

I'm not really sure what <your code here> should look like; my first
stab was

          obj <- new("relimplmbooteval")
          slots <- slotNames(from)
          for (slt in slots)
              slot(obj, slt) <- slot(from, slt)
          obj

which would not be very memory efficient (each slot assignment copies
the entire object) but is perhaps fine for your needs.

Hope that helps

Martin

Ulrike Grömping <[hidden email]> writes:

> Dear developeRs,
>
> with R 2.4.1 (and also 2.4.0), the function str() fails on objects of class
> relimplmbooteval, if there are unused slots, which is very often the case. I
> am not sure whether this is a bug in str() or a correct behavior of str()
> that unmasks some sloppiness in my usage of S4 classes (that I am not aware
> of)?
>
> Reproducible example (package relaimpo needed):
>
> The program
>
> require(relaimpo)
> bte<-booteval.relimp(boot.relimp(swiss,b=100))
> str(bte)
>
> yields the error message
>
> Errorr in FUN(c("lmg.lower", "lmg.upper", "lmg.rank.lower",
> "lmg.rank.upper",  :
>         no slot named "pmvd.lower" for this object of class
> "relimplmbooteval"
> (back-translated from German).
>
> Regards, Ulrike
> --
> View this message in context: http://www.nabble.com/Bug-in-str-or-issue-with-class-management-in-my-package--tf3453429.html#a9633559
> Sent from the R devel mailing list archive at Nabble.com.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

--
Martin Morgan
Bioconductor / Computational Biology
http://bioconductor.org

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

Re: Bug in str or issue with class management in my package?

Ulrike Groemping
Martin,

thank you, you've pointed me in the right direction! I just wasn't aware that a slot must not be unassigned (everything but str worked so far, and even str works in R 2.3.1).

Actually, looking up the help for function new, I see that the solution is much easier, because my class relimplmbooteval extends the class relimplm of the object ausgabe. Therefore, I can simply write
          obj <- new("relimplmbooteval", ausgabe)
which copies all slots from ausgabe to the right place in the new obj.

Regards, Ulrike

Martin Morgan wrote
Ulrike,

booteval.relimp has the statement

    ausgabe <- calc.relimp(empcov, type = type, diff = diff,
        rank = rank, rela = rela, always = always, groups = groups,
        groupnames = groupnames)
    class(ausgabe) <- "relimplmbooteval"

This changes the name of the class of ausgabe, without changing its
structure. I'm guessing that prior to this call ausgabe did not have a
slot "pmvd.lower". Here's the simpler version:

>setClass("A", representation=representation(x="numeric"))
[1] "A"
> setClass("B", contains="A", representation=representation(y="numeric"))
[1] "B"
> a <- new("A")
> class(a) <- "B"
> str(a)
Error in FUN(c("y", "x")[[1L]], ...) : no slot of name "y" for this object of class "B"

and some behavior which is somehow weird:

> slot(a, "y")
Error in slot(a, "y") : no slot of name "y" for this object of class "B"
> slot(a, "y") <- 10 # 'creates' the slot!
> slot(a, "y")
[1] 10

Probably what you want to do is to create a 'setAs' method

setAs('relimplm', 'relimplmbooteval',
      function(from) {
          <your code here, e.g.,>
      })

and use

    ausgabe <- as(ausgabe, "relimplmbooteval")

I'm not really sure what <your code here> should look like; my first
stab was

          obj <- new("relimplmbooteval")
          slots <- slotNames(from)
          for (slt in slots)
              slot(obj, slt) <- slot(from, slt)
          obj

which would not be very memory efficient (each slot assignment copies
the entire object) but is perhaps fine for your needs.

Hope that helps

Martin

Ulrike Grömping <groemp@tfh-berlin.de> writes:

> Dear developeRs,
>
> with R 2.4.1 (and also 2.4.0), the function str() fails on objects of class
> relimplmbooteval, if there are unused slots, which is very often the case. I
> am not sure whether this is a bug in str() or a correct behavior of str()
> that unmasks some sloppiness in my usage of S4 classes (that I am not aware
> of)?
>
> Reproducible example (package relaimpo needed):
>
> The program
>
> require(relaimpo)
> bte<-booteval.relimp(boot.relimp(swiss,b=100))
> str(bte)
>
> yields the error message
>
> Errorr in FUN(c("lmg.lower", "lmg.upper", "lmg.rank.lower",
> "lmg.rank.upper",  :
>         no slot named "pmvd.lower" for this object of class
> "relimplmbooteval"
> (back-translated from German).
>
> Regards, Ulrike
> --
> View this message in context: http://www.nabble.com/Bug-in-str-or-issue-with-class-management-in-my-package--tf3453429.html#a9633559
> Sent from the R devel mailing list archive at Nabble.com.
>
> ______________________________________________
> R-devel@r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

--
Martin Morgan
Bioconductor / Computational Biology
http://bioconductor.org

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Bug in str or issue with class management in my package?

Martin Maechler
Hi,

>>>>> "Ulrike" == Ulrike Grömping <[hidden email]>
>>>>>     on Fri, 23 Mar 2007 08:39:32 -0700 (PDT) writes:

    Ulrike> Martin,

    Ulrike> thank you, you've pointed me in the right direction! I just wasn't aware
    Ulrike> that a slot must not be unassigned (everything but str worked so far, and
    Ulrike> even str works in R 2.3.1).

That "everything worked" is actually quite astonishing to me.

I'd have expected that you should get an *error* when using

  class(<S4-object>) <- "arbitraryString"

since - as Martin Morgan mentioned - you typically coerce
S4 objects to a new class by  as(<..>, "new class")
                              ~~~~~~~~~~~~~~~~~~~~~
[ which either needs an explicit  SetAs(from,to, ....)
  declaration ``earlier on'' (typically by one of the class
  designers, often package authors),
  or an implicit one - as in your case, when one class extends
  another ]

Martin Mächler, ETH Zurich



    Ulrike> Actually, looking up the help for function new, I see that the solution is
    Ulrike> much easier, because my class relimplmbooteval extends the class relimplm of
    Ulrike> the object ausgabe. Therefore, I can simply write
    Ulrike> obj <- new("relimplmbooteval", ausgabe)
    Ulrike> which copies all slots from ausgabe to the right place in the new obj.

    Ulrike> Regards, Ulrike


    Ulrike> Martin Morgan wrote:
    >>
    >> Ulrike,
    >>
    >> booteval.relimp has the statement
    >>
    >> ausgabe <- calc.relimp(empcov, type = type, diff = diff,
    >> rank = rank, rela = rela, always = always, groups = groups,
    >> groupnames = groupnames)
    >> class(ausgabe) <- "relimplmbooteval"
    >>
    >> This changes the name of the class of ausgabe, without changing its
    >> structure. I'm guessing that prior to this call ausgabe did not have a
    >> slot "pmvd.lower". Here's the simpler version:
    >>
    >>> setClass("A", representation=representation(x="numeric"))
    >> [1] "A"
    >>> setClass("B", contains="A", representation=representation(y="numeric"))
    >> [1] "B"
    >>> a <- new("A")
    >>> class(a) <- "B"
    >>> str(a)
    >> Error in FUN(c("y", "x")[[1L]], ...) : no slot of name "y" for this object
    >> of class "B"
    >>
    >> and some behavior which is somehow weird:
    >>
    >>> slot(a, "y")
    >> Error in slot(a, "y") : no slot of name "y" for this object of class "B"
    >>> slot(a, "y") <- 10 # 'creates' the slot!
    >>> slot(a, "y")
    >> [1] 10
    >>
    >> Probably what you want to do is to create a 'setAs' method
    >>
    >> setAs('relimplm', 'relimplmbooteval',
    >> function(from) {
    >> <your code here, e.g.,>
    >> })
    >>
    >> and use
    >>
    >> ausgabe <- as(ausgabe, "relimplmbooteval")
    >>
    >> I'm not really sure what <your code here> should look like; my first
    >> stab was
    >>
    >> obj <- new("relimplmbooteval")
    >> slots <- slotNames(from)
    >> for (slt in slots)
    >> slot(obj, slt) <- slot(from, slt)
    >> obj
    >>
    >> which would not be very memory efficient (each slot assignment copies
    >> the entire object) but is perhaps fine for your needs.
    >>
    >> Hope that helps
    >>
    >> Martin
    >>
    >> Ulrike Grömping <[hidden email]> writes:
    >>
    >>> Dear developeRs,
    >>>
    >>> with R 2.4.1 (and also 2.4.0), the function str() fails on objects of
    >>> class
    >>> relimplmbooteval, if there are unused slots, which is very often the
    >>> case. I
    >>> am not sure whether this is a bug in str() or a correct behavior of str()
    >>> that unmasks some sloppiness in my usage of S4 classes (that I am not
    >>> aware
    >>> of)?
    >>>
    >>> Reproducible example (package relaimpo needed):
    >>>
    >>> The program
    >>>
    >>> require(relaimpo)
    >>> bte<-booteval.relimp(boot.relimp(swiss,b=100))
    >>> str(bte)
    >>>
    >>> yields the error message
    >>>
    >>> Errorr in FUN(c("lmg.lower", "lmg.upper", "lmg.rank.lower",
    >>> "lmg.rank.upper",  :
    >>> no slot named "pmvd.lower" for this object of class
    >>> "relimplmbooteval"
    >>> (back-translated from German).
    >>>
    >>> Regards, Ulrike
    >>> --
    >>> View this message in context:
    >>> http://www.nabble.com/Bug-in-str-or-issue-with-class-management-in-my-package--tf3453429.html#a9633559
    >>> Sent from the R devel mailing list archive at Nabble.com.
    >>>
    >>> ______________________________________________
    >>> [hidden email] mailing list
    >>> https://stat.ethz.ch/mailman/listinfo/r-devel
    >>
    >> --
    >> Martin Morgan
    >> Bioconductor / Computational Biology
    >> http://bioconductor.org
    >>
    >> ______________________________________________
    >> [hidden email] mailing list
    >> https://stat.ethz.ch/mailman/listinfo/r-devel
    >>
    >>

    Ulrike> --
    Ulrike> View this message in context: http://www.nabble.com/Bug-in-str-or-issue-with-class-management-in-my-package--tf3453429.html#a9637517
    Ulrike> Sent from the R devel mailing list archive at Nabble.com.

    Ulrike> ______________________________________________
    Ulrike> [hidden email] mailing list
    Ulrike> 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: Bug in str or issue with class management in my package?

Ulrike Grömping-2
Martin,
I agree, if the naive changing of class (like also in  Martina Morgan's simpler example below) causes issues later, it would be best if it throws an error straight away. That would have forced me to think about the correct way of changing the class immediately.
I have experienced no problems with "my way" so far in my package, all methods on objects of the class in question work without trouble; but that may be due to the fact that I payed attention in the methods that slots are only used if they exist.
Regards, Ulrike

> Hi,
>
> >>>>> "Ulrike" == Ulrike Grömping <[hidden email]>
> >>>>>     on Fri, 23 Mar 2007 08:39:32 -0700 (PDT) writes:
>
>    Ulrike> Martin,
>
>    Ulrike> thank you, you've pointed me in the right direction! I just wasn't aware
>    Ulrike> that a slot must not be unassigned (everything but str worked so far, and
>    Ulrike> even str works in R 2.3.1).
>
> That "everything worked" is actually quite astonishing to me.
>
> I'd have expected that you should get an *error* when using
>
>  class(<S4-object>) <- "arbitraryString"
>
> since - as Martin Morgan mentioned - you typically coerce
> S4 objects to a new class by  as(<..>, "new class")
>                             ~~~~~~~~~~~~~~~~~~~~~
> [ which either needs an explicit  SetAs(from,to, ....)
>  declaration ``earlier on'' (typically by one of the class
>  designers, often package authors),
>  or an implicit one - as in your case, when one class extends
>  another ]
Simple example from Martin Morgan, how "manual change" of class attribute works:

>    > setClass("A", representation=representation(x="numeric"))
>     [1] "A"
>    > setClass("B", contains="A", representation=representation(y="numeric"))
>     [1] "B"
>    > a <- new("A")
>    > class(a) <- "B"
>    > str(a)
>     Error in FUN(c("y", "x")[[1L]], ...) : no slot of name "y" for this object
>     of class "B"
>    
>     and some behavior which is somehow weird:
>    
>    > slot(a, "y")
>     Error in slot(a, "y") : no slot of name "y" for this object of class "B"
>    > slot(a, "y") <- 10 # 'creates' the slot!
>    > slot(a, "y")
>     [1] 10
------- End of Original Message -------
 

        [[alternative HTML version deleted]]


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