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

Gabriel Becker g@bembecker @end|ng |rom gm@||@com
Tue Mar 26 23:01:01 CET 2019

Hi Abs,

Lets try to remain civil even when disagreeing about major design
philosophies, ok?

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

> If I can merge this thread with the one I started yesterday...
> > "If the object does not have a class attribute, it has an implicit
> class..."
> > which I take to mean that if an object does have a class attribute it
> does not also have an implicit class.
> > I think this is reasonable behavior. Consider the "Date" class, which
> stores values as "numeric":
> > > class(Sys.Date())
> > [1] "Date"
> > > inherits(Sys.Date(),"numeric")
> > [1] FALSE
> > > class(unclass(Sys.Date()))
> > [1] "numeric"
> > > Sys.Date()%%2
> > Error in Ops.Date(Sys.Date(), 2) : %% not defined for "Date" objects
> > Letting the modulus operator (as one example) inherit the numeric class
> here could create problems.
> I disagree.
> A date object should probably extend integers rather than numerics, in the
> first place.
> However, if it extends numeric, then it extends numeric, otherwise it's a
> contradiction.
> So, inherits(Sys.Date(),"numeric") should return true.

You seem to be approaching the S3 "class"/dispatch system as something that
it is not: a formal class system. S3 dispatch is based, essentially, on
labeling, via the class attribute (or, if you like, the value returned by
class(), this is basically the same with some fiddly bits for S4, judging
by a quick glance at src/main/attrib.c:do_class ). If it is not in the set
of class labels, S3 dispatch *will not* treat it as that class. This is by
design. An S3 object's "class" also has no* bearing on the contents of the
object (* this isn't true for some built in atomic vector classes, as I
Recall, but it is for all user defined classes).

> mylist = list("hi", "what?")

> class(mylist) = "Date"

> mylist

[1] NA NA

*Warning messages:*

*1: In as.POSIXlt.Date(x) : NAs introduced by coercion*

*2: In as.POSIXlt.Date(x) : NAs introduced by coercion*

See? the print method looks at the class attribute of mylist, and says "Oh,
this is a Date, I'll use print.Date" and then it craps out (with NAs
instead of errors, but still) because the data contained within the object
isn't really a "Date". But there is no definition of what it means to be an
S3 "Date" object anywhere, other than that it has the Date class attribute.

All of the above is *by design*. You're welcome to not like the design. I
prefer the formalism of S4, myself, and there are various things I don't
love about how S3 works - including some but not all of the things that
have come up here. That said, the behaviors are not bugs, and any of the
changes you seem to be advocating for would not only break lots of code,
but would also represent fundamental changes to the design of a core aspect
of the R language.

As for doing %% on Dates, I seriously doubt anyone who is operating on Date
objects and thinking about times and dates is looking to do a modulo
operation in number of Days since Jan 1st 1970, which is what that
operation would do. Better to have that fail and if that really, for sure
is what the user actually wants to do, they can uncalss it or otherwise
convert it to a numeridc first.

> Modulo operators should be defined for both dates and numerics.
> However, the application of modulo operators to dates, is perhaps unclear,
> at least in the general case, anyway.
> > so instead of hitting utils:::head.function, it hits
> utils:::head.default
> > I also see this behavior at least as far aback as 3.5.1, so its not new
> to 3.5.3.

> These seem like significant design flaws.
> Implicit classes or whatever you want to call them, are clearly part of
> the class hierarchy.

I'm not sure what is clear about that, or what class hierarchy you're
talking about in the S3 case. Remember that S3 classes *have no formal
definitions at all*. Thats why I rarely if ever use them in software that I
write. But it's an important point here. What something would becomes if
you unclass()ed it has no bearing on what S3 dispatch will do.

> They should be included in inherits(), is() and standard method dispatch,
> regardless of whether they are part of the class vector or not.

Dispatch is ONLY done on the class vector for S3 (AFAIK). Only. That is how
S3 dispatch is defined and designed.

> Also, is this something that was introduced in R 3.5.1?
> The only thing worse than a design flaw is a design flaw that isn't
> backward compatible.

No that is just the non-devel R I had handy, and 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.
Before that head() on a function (likely) would have failed just like it
still does on your reclassed function. Because, again, this is how S3 is
supposed to behave when you give it the inputs you are. I fyou want your f
class to hit function S3 methods, you need to do

class(myfun) <- c("f", "function")

Then everything will work.


	[[alternative HTML version deleted]]

More information about the R-devel mailing list