Please don't do this to get the underlying vector length (or to achieve anything else). Setting/deleting attributes of an R object without checking the reference count violates R semantics, which in turn can have unpredictable results on R programs (essentially undebuggable segfaults now or more likely later when new optimizations or features are added to the language). Setting attributes on objects with reference count (currently NAMED value) greater than 0 (in some special cases 1 is ok) is cheating - please see Writing R Extensions - and getting speedups via cheating leads to fragile, unmaintainable and buggy code. Doing so in packages is particularly unhelpful to the whole community - packages should only use the public API as documented.

Similarly, getting a physical address of an object to hack around whether R has copied it or not should certainly not be done in packages and R code should never be working with or even obtaining physical address of an object. This is also why one cannot obtain such address using base R (apart in textual form from certain diagnostic messages where it can indeed be useful for low-level debugging).

Tomas

On 09/02/2018 01:19 AM, Dénes Tóth wrote:
The solution below introduces a dependency on data.table, but otherwise it does what you need:

---

# special method for Foo objects
length.Foo <- function(x) {
  length(unlist(x, recursive = TRUE, use.names = FALSE))
}

# an instance of a Foo object
x <- structure(list(a = 1, b = list(b1 = 1, b2 = 2)), class = "Foo")

# its length
stopifnot(length(x) == 3L)

# get its length as if it were a standard list
.length <- function(x) {
  cls <- class(x)
  # setattr() does not make a copy, but modifies by reference
  data.table::setattr(x, "class", NULL)
  # get the length
  len <- base::length(x)
  # re-set original classes
  data.table::setattr(x, "class", cls)
  # return the unclassed length
  len
}

# to check that we do not make unwanted changes
orig_class <- class(x)

# check that the address in RAM does not change
a1 <- data.table::address(x)

# 'unclassed' length
stopifnot(.length(x) == 2L)

# check that address is the same
stopifnot(a1 == data.table::address(x))

# check against original class
stopifnot(identical(orig_class, class(x)))

---


On 08/24/2018 07:55 PM, Henrik Bengtsson wrote:
Is there a low-level function that returns the length of an object 'x'
- the length that for instance .subset(x) and .subset2(x) see? An
obvious candidate would be to use:

.length <- function(x) length(unclass(x))

However, I'm concerned that calling unclass(x) may trigger an
expensive copy internally in some cases.  Is that concern unfounded?

Thxs,

Henrik

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


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

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

Reply via email to