[Rd] Discrepancy between is.list() and is(x, "list")

Gabriel Becker g@bembecker @end|ng |rom gm@||@com
Wed Mar 27 04:46:21 CET 2019

Abs et al,

Ok, so I have just gone and re-read the docs again. My language was a more
absolute than it should have been; *however*, I was still correct for the
cases under discussion.

From ?UseMethod (emphasis mine)

An R object is a data object which has a ‘class’ attribute (and

     this can be tested by ‘is.object’).  A class attribute is a

     character vector giving the names of the classes from which the

     object _inherits_.  *If the object does not have a class attribute,*

*     it has an implicit class.*  Matrices and arrays have class

     ‘"matrix"’ or‘"array"’ followed by the class of the underlying

     vector.  Most vectors have class the result of ‘mode(x)’, except

     that integer vectors have class ‘c("integer", "numeric")’ and real

     vectors have class ‘c("double", "numeric")’.

So, there are implicit classes, but *only when the data object is NOT an "R
object" (ie when it does NOT have a class attribute).* So, what I said was
not correct for certain built in classes: matrices, arrays, and some
atomic vectors but IS true of any object you assign a class attribute to
(e.g. by doing class<-() ) When your code classes an object, you have to
give the full desired vector of inheritence in its class attribute.
Anything you leave out just won't be there.

This is the case with your "f" classed object, so it *does not have an
implicit class.*  That is how S3 is designed and intended to work.

On Tue, Mar 26, 2019 at 6:42 PM Abs Spurdle <spurdle.a using gmail.com> wrote:

> > you had seemed to be presenting it as something new in 3.5.3. I would be
> surprised if the behavior doesn't go all the way back to whenever
> head.function was added.
> My bad.
> I'm just surprised I've never noticed these problems before.
> > S3 classes have no formal definitions at all
> > I'm not sure what is clear about that, or what class hierarchy you're
> talking about in the S3 case.
> That's questionable.
> One, because it depends on how you define formal definitions.

I mean, I guess, in the sense that that is true of any argument anyone ever
makes that uses a term.

For the record here, I'm using "Formal class definition" as an explicit
declaration of how valid objects of a particular class are structured, what
data they contain, and how they behave.

S3 does not have that. IT has only *implicit* class structure/content
definitions based on what methods for that class look for in objects passed
to them. There is no where you can look to figure out what it "means to be
a ____ class object" in the S3 sense, beyond a nebulous set of methods
which look for various things within an object that supposedly is of that

> x = "not a date"

> class(x) = "Date"

> is(x, "Date")

[1] TRUE

> y = Sys.Date()

> y

[1] "2019-03-26"

> attr(y, "class")

[1] "Date"

> is.object(y)

[1] TRUE

> class(y) = "NonDate"

> y

[1] 17981


[1] "NonDate"

> is(y, "Date")


> inherits(y, "Date")


> And two, because class definitions can exist outside the code itself.
> e.g. As part of an object oriented model.
> (Being "Object Oriented" is just as much about models as it is about
> syntax).

Again, I suppose? In fact they have to S3, as I just pointed out above.
But, I really don't see how this is relevant. I doesn't matter what you
have written down on paper, or in documentation, or in your head as a model
about how your S3 classes relate to eachother, because the S3 dispatch
machinery can't see into any of those places. It can only go by what you
put in the class vector, and that is all it is going to go by (for objects
with a class attribute, ie for any "classes" your code defines)

> Furthermore, when you change the class of a vector, list or function, much
> of the original object's structure and behavior remains.

Conjecture here, since I don't know what exact behaviors you're referring
to, but if they are ostensibly S3 based (ie they are invoved via an S3
generic), its probably becuse they hit *.default methods which call down to
code internal C which operates based on SEXP type, ie they "escape S3
dispatch" in a sense.

> So, it has "Inherited" or "Extended", in my opinion.
Resulting in a class hierarchy.

You're welcome to have that opinion, but simply put that is now how
inheritance *for the purposes of S3 dispatch* is defined in S3.

> > Dispatch is ONLY done on the class vector for S3 (AFAIK)

> Incorrect.
> We've already mentioned the example of head.function().
> In general, this dispatch occurs without the presence of a class attribute.

I said the class vector, as in what is returned by class().

 > class(rnorm)

[1] "function"

> attr(rnorm, "class")


I apologize for not more carefully delineating those two things.

That IS consistent with head hitting head.function for a function but
head.default for a "classed function", because according to the definition
of how S3 behaves, your "classed function" doesn't have any implicit
classes, and you didn't declare that it inherited from the function class.

 The portion that is incorrect with what I said is that if the data object
is NOT an R object, (ie it is an unclassed atomic vector or other built in
type - is.object() returns FALSE ) it MAY have an implicit class which will
affect S3 dispatch. But your "f" classed object does not.

> You seem to be approaching the S3 "class"/dispatch system as something
> that it is not: a formal class system
> If I can diverge...
> Where did this term "Formal Class System" come from?
> I've never seen it used anywhere else.
> Is is specific to R?

No. I'm not using it as a term of art at all, really. I'm using it to mean
explicit, non-implicit, that classes declare formal required internal
structures, etc.


	[[alternative HTML version deleted]]

More information about the R-devel mailing list