[Rd] True length - length(unclass(x)) - without having to call unclass()?

Tomas Kalibera tom@@@k@liber@ @ending from gm@il@com
Mon Sep 3 11:49:16 CEST 2018


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 using r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>
> ______________________________________________
> R-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list