From maechler at stat.math.ethz.ch  Mon Jul  5 11:47:01 2010
From: maechler at stat.math.ethz.ch (Martin Maechler)
Date: Mon, 5 Jul 2010 11:47:01 +0200
Subject: [Rd] Attributes of 1st argument in ...
In-Reply-To: <AANLkTilr6wTa3-twDfWL3z13lq5Gxz9-lHrvvF-hyjJj@mail.gmail.com>
References: <AANLkTinkSMoLfFm5MGQwA5AGSkVvEEZJhw0GbhKYZ4lB@mail.gmail.com>
	<AANLkTimfOOA7u9pR3pDL-B0vMcunguwC0taMH7bHxlvT@mail.gmail.com>
	<AANLkTikqDu4eFMQd6tsUE9FW82GehHQxhfbMFV_tk3Hy@mail.gmail.com>
	<alpine.LFD.2.00.1007041223300.30947@gannet.stats.ox.ac.uk>
	<AANLkTilr6wTa3-twDfWL3z13lq5Gxz9-lHrvvF-hyjJj@mail.gmail.com>
Message-ID: <19505.43541.43754.85521@lynne.math.ethz.ch>

>>>>> "DM" == Daniel Murphy <chiefmurphy at gmail.com>
>>>>>     on Sun, 4 Jul 2010 11:11:43 -0700 writes:

    DM> Thank you, Professor, for drawing my attention to the nifty tracemem
    DM> function. I'm using the ..1 syntax to check the properties of the S4 class
    DM> at function call.

    DM> The Description at ?"cBind" tells me that I'm not alone in this predicament.


    DM> Just as Matrix needs its own cBind function, my package will need its own
    DM> cbindMondate function. Alas, subclasses of mondate will also need their own
    DM> binding functions, thus defeating one of the purposes of the class paradigm
    DM> (for binding, anyway).

I don't think you see the full picture:

Matrix::cBind() builds on methods::cbind2()

and cbind2 / rbind2  are there (in package methods) for you to
use setMethod() on them.

BTW: When Matrix::cBind() -- and cbind2 / rbind2 in package
     methods were written,

R did not have the possibility yet to write methods for "...",
which it now does.

In the package Rmpfr (arbitrary-precision number ["mpfr"] computing),
where I also define methods for matrices of such "mpfr" numbers
(classes "mpfrMatrix" and "mpfrArray"),
I use the new feature of defining methods for "..." :

setGeneric("cbind", signature = "...")

setMethod("cbind", "Mnumber",
	  function(..., deparse.level = 1) {
	      args <- list(...)
	      if(all(sapply(args, is.atomic)))
		  return( base::cbind(..., deparse.level = deparse.level) )
	      ## else: at least one is "mpfr(Matrix/Array)"

	      if(any(sapply(args, is.character))) {
		  ## result will be  <character> matrix !
		  isM <- sapply(args, is, class2 = "mpfr")
		  args[isM] <- lapply(args[isM], as, Class = "character")
		  return(do.call(base::cbind,
				 c(args, list(deparse.level=deparse.level))))

	      } else if(any(sapply(args, is.complex))) {
		  ## result will be  <complex> matrix;
		  ## in the future <complex_mpfr>  ???

		  stop("cbind(...) of 'complex' and 'mpfr' objects is not implemented")
		  ## give at least warning !!
              }
              ## else

     ..........
     ..........
  })


where I use a useful class union

  setClassUnion("Mnumber",
		members = c("array_or_vector", # *but* must be numeric-like
		"mpfr", "mpfrArray", "mpfrMatrix"))

----

As always, I'd recommend to read the R source, rather than just
investigate the installed package.
You can get the *source* tarbal, i.e., the *.tar.gz file from
CRAN, or, as it's all on R-forge,
     http://rmpfr.r-forge.r-project.org/
you can get the source tarball here,
   https://r-forge.r-project.org/R/?group_id=386
or browse the source at
   https://r-forge.r-project.org/scm/viewvc.php/pkg/?root=rmpfr

But if I were you I'd get it via
   svn checkout svn://svn.r-forge.r-project.org/svnroot/rmpfr/pkg Rmpfr



    DM> As an aside, I wonder why, on around line 75, cBind uses 'rep.int("",
    DM> ncol(r))' rather than the slightly faster 'character(ncol(r))'.

Well, I would not remember, but the first one is a more self-explaining,
... and I would guess strongly that time difference is
irrelevant in the context where it's used...
... but then thanks for your hint :-)

Martin


    DM> Thanks again,
    DM> Dan

    DM> On Sun, Jul 4, 2010 at 4:36 AM, Prof Brian Ripley <ripley at stats.ox.ac.uk>wrote:

    >> I think you have missed the use of ..1 etc: see e.g. cBind() in package
    >> Matrix.
    >> 
    >> So x <- attr(list(...)[[1L]], "foo") can be x <- attr(..1, "foo")
    >> 
    >> As for 'extra copying', it all depends on exactly what you are doing, but
    >> compare
    >> 
    >> foo1 <- function(...) length(..1)
    >>> foo2 <- function(...) length(list(...)[[1L]])
    >>> tracemem(x <- runif(1000))
    >>> 
    >> [1] "<0x1b27800>"
    >> 
    >>> foo1(x)
    >>> 
    >> [1] 1000
    >> 
    >>> tracemem(x <- runif(1000))
    >>> 
    >> [1] "<0x1b29800>"
    >> 
    >>> foo2(x)
    >>> 
    >> tracemem[0x1b29800 -> 0x10a2200]: foo2
    >> [1] 1000
    >> 
    >> 
    >> 
    >> <snip>
    >> --
    >> Brian D. Ripley,                  ripley at stats.ox.ac.uk
    >> Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
    >> University of Oxford,             Tel:  +44 1865 272861 (self)
    >> 1 South Parks Road,                     +44 1865 272866 (PA)
    >> Oxford OX1 3TG, UK                Fax:  +44 1865 272595
    >> 

    DM> [[alternative HTML version deleted]]

    DM> ______________________________________________
    DM> R-devel at r-project.org mailing list
    DM> https://stat.ethz.ch/mailman/listinfo/r-devel



[Rd] Attributes of 1st argument in ...
Martin Maechler