Why aren't these problems taken more seriously?
They are taken seriously. But there are serious semantic differences
between S3, S4 and base type checking functions. The S3/S4 integration
should be viewed as a tool that is useful in practice, despite forced
compromises.
There are changes that would resolve some of these issues, like those
suggested earlier in this thread, but it's likely too disruptive to
make them now. Energy is better spent thinking about how we will do it
"right" the next time around.
Michael
On Wed, May 16, 2018 at 8:33 AM, Herv? Pag?s <hpages at fredhutch.org> wrote:
On 05/15/2018 09:13 PM, Michael Lawrence wrote:
My understanding is that array (or any other structure) does not
"simply" inherit from vector, because structures are not vectors in
the strictest sense. Basically, once a vector gains attributes, it is
a structure, not a vector. The methods package accommodates this by
defining an "is" relationship between "structure" and "vector" via an
"explicit coerce", such that any "structure" passed to a "vector"
method is first passed to as.vector(), which strips attributes. This
is very much by design.
It seems that the problem is really with matrices and arrays, not
with "structures" in general:
f <- factor(c("z", "x", "z"), levels=letters)
m <- matrix(1:12, ncol=3)
df <- data.frame(f=f)
x <- structure(1:3, titi="A")
Only the matrix looses its attributes when passed to a "vector"
method:
setGeneric("foo", function(x) standardGeneric("foo"))
setMethod("foo", "vector", identity)
foo(f) # attributes are preserved
# [1] z x z
# Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
foo(m) # attributes are stripped
# [1] 1 2 3 4 5 6 7 8 9 10 11 12
foo(df) # attributes are preserved
# f
# 1 z
# 2 x
# 3 z
foo(x) # attributes are preserved
# [1] 1 2 3
# attr(,"titi")
# [1] "A"
Also if structures are passed to as.vector() before being passed to
a "vector" method, shouldn't as.vector() and foo() be equivalent on
them? For 'f' and 'x' they're not:
as.vector(f)
# [1] "z" "x" "z"
as.vector(x)
# [1] 1 2 3
Finally note that for factors and data frames the "vector" method gets
selected despite the fact that is( , "vector") is FALSE:
is(f, "vector")
# [1] FALSE
is(m, "vector")
# [1] TRUE
is(df, "vector")
# [1] FALSE
is(x, "vector")
# [1] TRUE
Couldn't we recognize these problems as real, even if they are by
design? Hopefully we can all agree that:
- the dispatch mechanism should only dispatch, not alter objects;
- is() and selectMethod() should not contradict each other.
Thanks,
H.
Michael
On Tue, May 15, 2018 at 5:25 PM, Herv? Pag?s <hpages at fredhutch.org>
wrote:
Hi,
This was quite unexpected:
setGeneric("foo", function(x) standardGeneric("foo"))
setMethod("foo", "vector", identity)
foo(matrix(1:12, ncol=3))
# [1] 1 2 3 4 5 6 7 8 9 10 11 12
foo(array(1:24, 4:2))
# [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
21
22 23
24
If I define a method for array objects, things work as expected though:
setMethod("foo", "array", identity)
foo(matrix(1:12, ncol=3))
# [,1] [,2] [,3]
# [1,] 1 5 9
# [2,] 2 6 10
# [3,] 3 7 11
# [4,] 4 8 12
So, luckily, I have a workaround.
But shouldn't the dispatch mechanism stay away from the business of
altering objects before passed to it?
Thanks,
H.
--
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: hpages at fredhutch.org
Phone: (206) 667-5791
Fax: (206) 667-1319