Skip to content

slots of type "double"

9 messages · Hervé Pagès, Simon Urbanek, John Chambers +2 more

#
Hi,

Any idea why S4 doesn't allow slots of type "double"?

  > setClass("A", representation(a="double"))
  Error in makePrototypeFromClassDef(properties, ClassDef, immediate, where) : 
    in making the prototype for class "A" elements of the prototype failed to
match the corresponding slot class: a (class ?double? )

"numeric", "integer", "character", "complex", "raw", etc... they all work
but "double" doesn't. Any reason for this strange exception?

Thanks!
H.
#
On Nov 13, 2007, at 3:36 AM, hpages at fhcrc.org wrote:

            
Type (as in storage type and "double" is a storage type) has nothing  
to do with classes. You cannot create slots for types, only for classes.
AFAICS there is no way to create an object of the class "double" (save  
for 'faking' it by creating an informal S3 object), so such definition  
is useless. And given this fact, even the internal code is unable to  
create it, so it doesn't match the signature. Note:

 > a=new("double")
 > class(a)
[1] "numeric"
 > is(a,"double")
[1] FALSE

I think it comes from the fact that there is an S4 definition for the  
class "double" which is not valid. That is probably a bug and the  
class definition should be removed.

Cheers,
Simon
#
On Tue, 13 Nov 2007, Simon Urbanek wrote:

            
Unfortunately not in the world of the 'methods' package (which seems to 
differ here from the Green Book and S-PLUS).  There's a basic class 
"double" (and also "single") defined in BasicClasses.R.  It say:
No Slots, prototype of class "numeric"

Extends: "vector", "numeric"
No Slots, prototype of class "numeric"

Extends: "vector"

Known Subclasses: "double", "integer"

So it is an otherwise unspecified subclass of "numeric".

Now when you do
[1] 3.141593
[1] "numeric"

you are in fact calling class() on a REALSXP, and that is set up to report 
"numeric" (the implicit class comes from mode not type, except for 
"integer").

Anther area of confusion is that as.numeric, as.double and as.real are 
three names for the same thing, but is.numeric and is.double are not the 
same.  So we end up with
[1] TRUE
[1] FALSE
[1] TRUE
[1] TRUE

Basically I think class() is wrong (it should use "double"), but it was 
not my choice and it was presumably done to agree with the Green Book.

I agree that it would be best to remove the "double" and "single" S4 
classes.  At least in the version of S-PLUS I have left, "double" does not 
exist -- "single" does but is a distinct storage type.

  
    
#
On Tue, 13 Nov 2007, John Chambers wrote:

            
Eliminate "double" and "single".
I was going to propose so after running some tests over CRAN/BioC (which 
will take a few hours).

Brian

  
    
#
On Tue, 13 Nov 2007, Prof Brian Ripley wrote:

            
Which showed up problems in packages Matrix and matlab.

Matrix clearly has a different view of these classes:

## "atomic vectors" (-> ?is.atomic ) --
## ---------------  those that we want to convert from old-style "matrix"
setClassUnion("atomicVector", ## numeric = {integer, double} but all 3 
should *directly* be atomic
               members = c("logical", "integer", "double", "numeric",
                           "complex", "raw", "character"))

If I remove "double" there, I get an error in an example:
+           identical(cm, as.numeric(scm)))
Error in as(x at x, mode) :
   no method or default for coercing "numeric" to "double"

and looking at the code suggests that "double" is used as the class name 
in several places.


Package matlab is simpler: test mkconstarray.R fails at

   > test.mkconstarray(list(class.type = "double", value = pi, size = 4), 
rep(pi, 4))
   Error in as(value, match.arg(class.type)) :
     no method or default for coercing "numeric" to "double"

and needs the author to rectify his confusion between "class" and "type".

I'd like to give the Matrix authors a chance to look into this before 
making the change.  Loking at the packages has reinforced my impression 
that having "double" as an S4 class is only adding confusion, so the 
change is desirable.
#
On Wed, November 14, 2007 09:09, Prof Brian Ripley wrote:
I think (without having had time to check all implications) that I agree
quite a bit.  I don't think that I was not partly confused about things,
either as they were in Matrix when I "entered the project" or as they
turned out to work or fail, when we started to use those class definitions
quite a few R versions back, when also "methods" / "base" may have behaved
a bit differently than now.
I must admit that I did not program according to documented behavior, but
rather to work behavior :-) ;-)

I'm very busy the rest of this week, in out'of'town meetings,
so won't be able to comment much more.
Martin
#
still found a bit time for more remarks.
MM> On Wed, November 14, 2007 09:09, Prof Brian Ripley
MM> wrote:
>> On Tue, 13 Nov 2007, Prof Brian Ripley wrote:
>>
>>> On Tue, 13 Nov 2007, John Chambers wrote:
>>> 
    >>>> What's the proposal here?  To eliminate "double" as a
    >>>> class?  No objection
    >>> 
    >>> Eliminate "double" and "single".
    >>> 
    >>>> from this corner.  As I remember, it was put in early
    >>>> in the implementation of methods, when I was confused
    >>>> about what R intended in this area (well, I'm not
    >>>> totally unconfused even now).
    >>>> 
    >>>> If this is the proposal, we could implement it in
    >>>> r-devel and see if there are complaints.
    >>> 
    >>> I was going to propose so after running some tests over
    >>> CRAN/BioC (which will take a few hours).
    >> 
    >> Which showed up problems in packages Matrix and matlab.


    >> Matrix clearly has a different view of these classes:
    >> 
    >> ## "atomic vectors" (-> ?is.atomic ) -- ##
    >> --------------- those that we want to convert from
    >> old-style "matrix" setClassUnion("atomicVector", ##
    >> numeric = {integer, double} but all 3 should *directly*
    >> be atomic members = c("logical", "integer", "double",
    >> "numeric", "complex", "raw", "character"))
    >> 
    >> If I remove "double" there, I get an error in an example:
    >> 
    >>> stopifnot(is(scm, "sparseVector"),
    >> + identical(cm, as.numeric(scm))) Error in as(x at x, mode)
    >> : no method or default for coercing "numeric" to "double"
    >> 
    >> and looking at the code suggests that "double" is used as
    >> the class name in several places.

yes.
As you mention and I had in the comment above,
I've worked from the premise of something like a class union of

 numeric = {integer, double} 

-- which corresponds to S3's    is.numeric()  which we all know
   differs from the semantic of as.numeric()

and now know why I had done so {empty lines deleted}:

  > showClass("numeric")
  No Slots, prototype of class "numeric"
  Extends: "vector"
  Known Subclasses: "double", "integer"

  > showClass("double")
  No Slots, prototype of class "numeric"
  Extends: "vector", "numeric"

  > showClass("integer")
  No Slots, prototype of class "integer"
  Extends: "vector", "numeric"

which you partially also mentioned in your initial posting.

As a 2nd thought I wonder if we should not keep this current
scheme and fix its behavior where needed (the problem the OP had):
The notion of   numeric := union(double, integer)
does now appeal to me again;
in particular since eliminating "double"  in the S4 world  will
not eliminate it from other places, and the basic problem of
is.numeric / as.numeric  inconsistency is - I think - not
something we'd want to eliminate, just because it would break too
much existing code (and books on S and R).

Of course I may have overlooked other reasonings;
as mentioned, I'm quite a bit time limited at the moment.
Martin

  [....]

    >> I'd like to give the Matrix authors a chance to look into
    >> this before making the change.  

Thanks, indeed!

    >> Loking at the packages has reinforced my impression that
    >> having "double" as an S4 class is only adding confusion,
    >> so the change is desirable.

well or maybe it's just the lack of comprehensive documentation
of S4 classes as in 'methods' in R -- where I think JMC did want
to do a few things slightly differently than they are in S-PLUS..


    MM> I think (without having had time to check all
    MM> implications) that I agree quite a bit.  I don't think
    MM> that I was not partly confused about things, either as
    MM> they were in Matrix when I "entered the project" or as
    MM> they turned out to work or fail, when we started to use
    MM> those class definitions quite a few R versions back,
    MM> when also "methods" / "base" may have behaved a bit
    MM> differently than now.  I must admit that I did not
    MM> program according to documented behavior, but rather to
    MM> work behavior :-) ;-)

    MM> I'm very busy the rest of this week, in out'of'town
    MM> meetings, so won't be able to comment much more.  Martin
#
In-line omments near the end:
On Wed, 14 Nov 2007, Martin Maechler wrote:

            
(It predates S3 classes, being in the Blue Book.  And what as.numeric does 
in R differs from the Blue Book description, although for a long time the 
R help gave the BB version.  But S also differs, at least in recent 
years.)
(I posted output from getClass, as showClass is not in the Green Book, 
although I actually used showClass first.)
I don't believe we can get from here to there without massive upheaval. 
"numeric" is not a virtual class, and making "double" the basic class and 
"numeric" a virtual one would break tons of code (and writeups).
(I do wonder if any of those books do get to that level of detail, and if 
they do what system they describe, given the divergence from the Blue 
Book.  I checked that the VR ones do not. I tend to agree with the BB 
comment that the storage type only matters in external interfaces, 
although that perhaps undervalues +/-Inf which may not have been 
available back then.)

I may be wrong, but I believe class "double" does not exist in the (strict 
sense) S4 world: it was certainly not in S-PLUS 6.2.

With a clean-sheet design we might well do things differently, and I think 
it would be possible for Matrix to make use of a class union of "numeric" 
and "integer".  But the name "numeric" is already taken and we are going 
to have to live with three names [*] for the same concept, and setting S3 
methods on as.double and S4 ones on as.numeric (because it would be too 
painful to change either).

Brian

[*] numeric, double, real.  My proposal to remove 'real' met with 
objections.