Two recent changes have been committed to r-devel, related to discussions on this list earlier: 1. setOldClass() has an argument prototype= to specify the default object for the class. If provided, the S3 class can be a slot in an S4 class, with a valid default object. (It's still not going to work well to have an S3 non-virtual class as a superclass of an S4 class. See the setOldClass help page.) 2. There is a heuristic test for S4 objects, seemsS4Object(), and a corresponding C-level test, R_seemsS4Object(object), both using the existence of a "package" attribute on class(object) as a test. The test is called seemsS4Object() rather than isS4Object() deliberately, but it should be fairly accurate. It will mistakenly identify an S3 object as S4 if the package attribute is there (possible, but hard to see why anyone would do this). It can make the opposite mistake, though, UNLESS the package generating the object is reinstalled with the current version of R, because older versions failed to put the attribute on some of the basic S4 classes (esp. classRepresentation). This is not by itself the right test for intercepting S3 code for certain primitives (c(), match(), [, for example), as was being discussed earlier. Only S4 objects that do not inherit from "vector" should be blocked. So the suitable test, in R code, is something like: if(seemsS4Object(x) && !is(x, "vector"))