On Sat, Mar 19, 2016 at 4:29 AM, Hervé Pagès <hpa...@fredhutch.org> wrote:
> On 03/19/2016 01:22 AM, Michael Lawrence wrote: > >> >> >> On Sat, Mar 19, 2016 at 12:10 AM, Hervé Pagès <hpa...@fredhutch.org >> <mailto:hpa...@fredhutch.org>> wrote: >> >> On 03/18/2016 03:28 PM, Michael Lawrence wrote: >> >> >> On Fri, Mar 18, 2016 at 2:53 PM, Hervé Pagès >> <hpa...@fredhutch.org <mailto:hpa...@fredhutch.org> >> <mailto:hpa...@fredhutch.org <mailto:hpa...@fredhutch.org>>> >> wrote: >> >> Hi, >> >> Short story >> ----------- >> >> setClassUnion("ArrayLike", "array") >> >> showClass("ArrayLike") # no slot >> >> setClass("MyArrayLikeConcreteSubclass", >> contains="ArrayLike", >> representation(stuff="ANY") >> ) >> >> showClass("MyArrayLikeConcreteSubclass") # 2 slots!! >> >> That doesn't seem right. >> >> Long story >> ---------- >> >> S4 provides at least 3 ways to create a little class >> hierarchy >> like this: >> >> FooLike ............. virtual class with no slot >> ^ ^ >> | | >> foo anotherfoo ..... 2 concrete subclasses >> >> (1) The "standard" way: define FooLike first, then foo and >> anotherfoo >> as subclasses of FooLike: >> >> setClass("FooLike") >> >> setClass("foo", >> contains="FooLike", >> representation(stuff="ANY") >> ) >> >> setClass("anotherfoo", >> contains="FooLike", >> representation(stuff="ANY") >> ) >> >> showClass("FooLike") # displays foo and anotherfoo as >> # known subclasses >> >> x1 <- new("foo") >> is(x1, "foo") # TRUE >> is(x1, "FooLike") # TRUE >> is(x1, "anotherfoo") # FALSE >> >> x2 <- new("anotherfoo") >> is(x2, "anotherfoo") # TRUE >> is(x2, "FooLike") # TRUE >> is(x2, "foo") # FALSE >> >> Everything works as expected. >> >> (2) Using a class union: define foo and anotherfoo first, >> then FooLike >> as the union of foo and anotherfoo: >> >> setClass("foo", representation(stuff="ANY")) >> setClass("anotherfoo", representation(stuff="ANY")) >> setClassUnion("FooLike", c("foo", "anotherfoo")) >> >> showClass("FooLike") # displays foo and anotherfoo as >> # known subclasses >> >> (3) Using a *unary* class union: define foo first, then >> FooLike as the >> (unary) union of foo, then anotherfoo as a subclass of >> FooLike: >> >> setClass("foo", representation(stuff="ANY")) >> setClassUnion("FooLike", "foo") >> >> showClass("FooLike") # displays foo as the only known >> subclass >> >> setClass("anotherfoo", >> contains="FooLike", >> representation(stuff="ANY") >> ) >> >> showClass("FooLike") # now displays foo and anotherfoo >> as >> # known subclasses >> >> The 3 ways lead to the same hierarchy. However the 3rd way is >> interesting because it allows one to define the FooLike >> virtual >> class as the parent of an existing foo class that s/he >> doesn't >> control. >> >> >> Why not use setIs() for this? >> >> >> > setClass("ArrayLike") >> > setIs("array", "ArrayLike") >> Error in setIs("array", "ArrayLike") : >> class “array” is sealed; new superclasses can not be defined, >> except by 'setClassUnion' >> >> How do you define a virtual class as the parent of an existing class >> with setIs? >> >> >> You can only do that with setClassUnion(). But the new classes should >> use setIs() to inherit from the union. So it's: >> >> setClassUnion("ArrayLike", "array") >> setClass("MyArrayLike") >> setIs("MyArrayLike", "ArrayLike") >> >> Everything then behaves as expected. I >> don't think it makes much sense to "contain" a class union. >> >> >> Why is that? A class union is just a virtual class with no slot >> that is the parent of the classes that are in the union. All the >> classes in the union contain their parent. What's interesting is that >> this union is actually open to new members: when I later define a new >> class that contains the class union, I'm just adding a new member to >> the union. >> >> Rather, you >> just want to establish the inheritance relationship. >> >> >> Isn't what I'm doing when I define a new class that contains the >> class union? >> >> >> Containing does two things: establishes the is() relationship and adds >> slots to the class. >> > > I understand that. But in that case, since a class union has no slots, > one would expect that using setIs() is equivalent to containing. > > These slots are comprised of the slots of the >> contained class, and as a special case the "array" class and other >> native types confer a data part that comes from the prototype of the >> class. The "array" class has a double vector with a dim attribute as its >> prototype. That is all well understood. What is surprising is that >> "ArrayLike" has the same prototype as "array". That happens via >> setIs(doComplete=TRUE), called by setClassUnion(). When a class gains >> its first non-virtual child, the parent assumes the prototype of its >> child. I'm not sure why, but the logic is very explicit and I've come >> to just accept it as a "feature". >> > > Never noticed that. Thanks for clarifying. So with this "feature": > > - setClassUnion("A", c("B", "C")) is not the same as > setClassUnion("A", c("C", "B")) > > - if 2 packages define concrete subclasses of a virtual > class defined in a 3rd package, the prototype of the virtual > class will depend on the order the packages are loaded > > - using setIs("MyArrayLike", "ArrayLike") is not equivalent > to containing (even though ArrayLike has no slots) > > - containing adds an undesirable .Data slot > > - containing breaks is.array() but not is( , "array") > > Seems pretty harmful to me. Would be good to understand the rationale > behind this feature. In particular it's not clear to me why a virtual > class with no slot would need to have a prototype at all (i.e. other > than NULL). > > I ran into this some months ago when >> defining my own ArrayLike when working on a very similar package to the >> one you are developing ;) >> > > After giving it more thoughts I realized that I can do without the > ArrayLike class. That will keep the class hierarchy in HDF5Array to the > strict minimum. > > Yea I've come to realize that declaring virtual classes that indicate whether an object behaves like a base type is overkill. It usually suffices to say that the object satisfies the basic contract of an array, list, vector, etc. It would be nice to have something like a Java interface for specifying such contracts. > Thanks for the feedback, > H. > > >> >> >> For example, to define an ArrayLike class: >> >> setClassUnion("ArrayLike", "array") >> showClass("ArrayLike") # displays array as a known >> subclass >> >> Note that ArrayLike is virtual with no slots (analog to a >> Java >> Interface), which is what is expected. >> >> setClass("MyArrayLikeConcreteSubclass", >> contains="ArrayLike", >> representation(stuff="ANY") >> ) >> >> showClass("MyArrayLikeConcreteSubclass") # shows 2 >> slots!! >> >> What is the .Data slot doing here? I would expect to see >> that slot >> if MyArrayLikeConcreteSubclass was extending array but this >> is not >> the case here. >> >> a <- new("MyArrayLikeConcreteSubclass") >> >> is(a, "MyArrayLikeConcreteSubclass") # TRUE --> ok >> is(a, "ArrayLike") # TRUE --> ok >> is(a, "array") # FALSE --> ok >> >> But: >> >> is.array(a) # TRUE --> not ok! >> >> Is is.array() confused by the presence of the .Data slot? >> >> >> It looks like the unary union somehow equates ArrayLike and array >> >> >> Clearly the unary union makes ArrayLike a parent of array, as it >> should >> be. This can be confirmed by extends(): >> >> > extends("array", "ArrayLike") >> [1] TRUE >> > extends("ArrayLike", "array") >> [1] FALSE >> >> The results for is(a, "ArrayLike") (TRUE) and is(a, "array") (FALSE) >> on a MyArrayLikeConcreteSubclass instance are consistent with this. >> >> So the little 3-class hierarchy I end up with in the above example >> is exactly how expected: >> >> ArrayLike >> ^ ^ >> | | >> array MyArrayLikeConcreteSubclass >> >> What is not expected is that MyArrayLikeConcreteSubclass has a .Data >> slot and that is.array(a) returns TRUE on a >> MyArrayLikeConcreteSubclass >> object. >> >> H. >> >> and >> thus makes ArrayLike confer a dim attribute (and thus is.array(a) >> returns TRUE). Since S4 objects cannot have attributes that are >> not >> slots, it must do this via a data part, thus the .Data slot. >> >> I can fix it by defining an "is.array" method for >> MyArrayLikeConcreteSubclass objects: >> >> setMethod("is.array", "MyArrayLikeConcreteSubclass", >> function(x) FALSE >> ) >> >> However, it feels that I shouldn't have to do this. >> >> Is the presence of the .Data slot in >> MyArrayLikeConcreteSubclass >> objects an unintended feature? >> >> Thanks, >> H. >> >> > sessionInfo() >> R Under development (unstable) (2016-01-07 r69884) >> Platform: x86_64-pc-linux-gnu (64-bit) >> Running under: Ubuntu 14.04.4 LTS >> >> locale: >> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C >> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8 >> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 >> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C >> [9] LC_ADDRESS=C LC_TELEPHONE=C >> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C >> >> attached base packages: >> [1] stats graphics grDevices utils datasets >> methods base >> >> -- >> Hervé Pagès >> >> Program in Computational Biology >> Division of Public Health Sciences >> Fred Hutchinson Cancer Research Center >> 1100 Fairview Ave. N, M1-B514 >> P.O. Box 19024 >> Seattle, WA 98109-1024 >> >> E-mail: hpa...@fredhutch.org <mailto:hpa...@fredhutch.org> >> <mailto:hpa...@fredhutch.org <mailto:hpa...@fredhutch.org>> >> Phone: (206) 667-5791 <tel:%28206%29%20667-5791> >> <tel:%28206%29%20667-5791> >> Fax: (206) 667-1319 <tel:%28206%29%20667-1319> >> <tel:%28206%29%20667-1319> >> >> ______________________________________________ >> R-devel@r-project.org <mailto:R-devel@r-project.org> >> <mailto:R-devel@r-project.org <mailto:R-devel@r-project.org>> >> mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel >> >> >> >> -- >> Hervé Pagès >> >> Program in Computational Biology >> Division of Public Health Sciences >> Fred Hutchinson Cancer Research Center >> 1100 Fairview Ave. N, M1-B514 >> P.O. Box 19024 >> Seattle, WA 98109-1024 >> >> E-mail: hpa...@fredhutch.org <mailto:hpa...@fredhutch.org> >> Phone: (206) 667-5791 <tel:%28206%29%20667-5791> >> Fax: (206) 667-1319 <tel:%28206%29%20667-1319> >> >> >> > -- > Hervé Pagès > > Program in Computational Biology > Division of Public Health Sciences > Fred Hutchinson Cancer Research Center > 1100 Fairview Ave. N, M1-B514 > P.O. Box 19024 > Seattle, WA 98109-1024 > > E-mail: hpa...@fredhutch.org > Phone: (206) 667-5791 > Fax: (206) 667-1319 > > [[alternative HTML version deleted]] ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel