From timhesterberg at gmail.com  Tue Dec 28 15:43:13 2010
From: timhesterberg at gmail.com (Tim Hesterberg)
Date: Tue, 28 Dec 2010 06:43:13 -0800
Subject: [Rd] aperm() should retain class of input object
In-Reply-To: <4D18BF9A.6040404@yorku.ca> (message from Michael Friendly on
	Mon, 27 Dec 2010 11:32:26 -0500)
References: <4D18BF9A.6040404@yorku.ca>
Message-ID: <yajf7heu9cvy.fsf@gmail.com>

Having aperm() return an object of the same class is dangerous, there
are undoubtedly classes for which that is not appropriate, producing an
illegal object for that class or quietly giving incorrect results.

Three alternatives are to:
* add the keep.class option but with default FALSE
* make aperm a generic function 
  - without a keep.class argument
  - with a ... argument
  - methods for classes like table could have keep.class = TRUE
* make aperm a generic function 
  - without a keep.class argument
  - with a ... argument
  - default method have keep.class = TRUE

The third option would give the proposed behavior by default, but
allow a way out for classes where the behavior is wrong.  This puts
the burden on a class author to realize the potential problem with
aperm, so my preference is one of the first two options.

>aperm() was designed for multidimensional arrays, but is also useful for
>table objects, particularly
>with the lattice, vcd and vcdExtra packages.  But aperm() was designed
>and implemented before other
>related object classes were conceived, and I propose a small tune-up to
>make it more generally useful.
>
>The problem is that  aperm() always returns an object of class 'array',
>which causes problems for methods
>designed for table objects. It also requires some package writers to
>implement both .array and .table
>methods for the same functionality, usually one in terms of the other.
>Some examples of unexpected, and initially perplexing results (when only
>methods for one class are implemented)
>are shown below.
>
>
> > library(vcd)
> > pairs(UCBAdmissions, shade=TRUE)
> > UCB <- aperm(UCBAdmissions, c(2, 1, 3))
> >
> > # UCB is now an array, not a table
> > pairs(UCB, shade=TRUE)
>There were 50 or more warnings (use warnings() to see the first 50)
> >
> > # fix it, to get pairs.table
> > class(UCB) <- "table"
> > pairs(UCB, shade=TRUE)
> >
>
>
>
>Of course, I can define a new function, tperm() that does what I think
>should be the expected behavior:
>
># aperm, for table objects
>
>tperm <- function(a, perm, resize = TRUE) {
>     result <- aperm(a, per, resize)
>     class(result) <- class(a)
>     result
>}
>
>But I think it is more natural to include this functionality in aperm()
>itself.  Thus, I propose the following
>revision of base::aperm(), at the R level:
>
>aperm <- function (a, perm, resize = TRUE, keep.class=TRUE)
>{
>     if (missing(perm))
>         perm <- integer(0L)
>     result <- .Internal(aperm(a, perm, resize))
>     if(keep.class) class(result) <- class(a)
>     result
>}
>
>
>I don't think this would break any existing code, except where someone
>depended on coercion to an array.
>The drop-in replacement for aperm would set keep.class=FALSE by default,
>but I think TRUE is  more
>natural.
>
>FWIW, here are the methods for table and array objects
>from my current (non-representative) session.
>
> > methods(class="table")
>  [1] as.data.frame.table barchart.table*     cloud.table*
>contourplot.table*  dotplot.table*
>  [6] head.table*         levelplot.table*    pairs.table*
>plot.table*         print.table
>[11] summary.table       tail.table*
>
>    Non-visible functions are asterisked
> >
> > methods(class="array")
>[1] anyDuplicated.array as.data.frame.array as.raster.array*
>barchart.array*     contourplot.array*  dotplot.array*
>[7] duplicated.array    levelplot.array*    unique.array
>
>
>--
>Michael Friendly     Email: friendly AT yorku DOT ca
>Professor, Psychology Dept.
>York University      Voice: 416 736-5115 x66249 Fax: 416 736-5814
>4700 Keele Street    Web:http://www.datavis.ca
>Toronto, ONT  M3J 1P3 CANADA



[Rd] aperm() should retain class of input object
Tim Hesterberg