16

is there a way to test whether two objects are identical in the R language?

For clarity: I do not mean identical in the sense of the identical function, which compares objects based on certain properties like numerical values or logical values etc.

I am really interested in object identity, which for example could be tested using the is operator in the Python language.

symbolrush
  • 7,123
  • 1
  • 39
  • 67
Sven Hager
  • 3,144
  • 4
  • 24
  • 32
  • 3
    For those not familiar with Python, can you elaborate on how you define identity (or lets say sameness)? In the strict sense an object can only be identical with itself. What would be the intended use of this test? – Roland Jun 06 '12 at 11:04
  • 1
    Do you mean object class? For example `is.numeric`? – Andrie Jun 06 '12 at 11:11
  • @Andrie and Roland: I mean identity in the sense of the same address in the main memory. For example, in a common language like Python or Java I could do something like (modulo syntax) b = new Object() c = b In this case, b and c point to the same object. – Sven Hager Jun 06 '12 at 11:18
  • http://stackoverflow.com/questions/2438667/what-is-the-semantics-of-is-operator-in-python – Ben Bolker Jun 06 '12 at 11:19
  • @joran: it might be interesting for reference classes (`?getRefClass`) ... ? – Ben Bolker Jun 06 '12 at 11:25
  • @MatthewDowle Indeed, I was confused. Sadly, I'm still quite a ways away from my "mistaken belief quota" for the day. – joran Jun 06 '12 at 11:40

2 Answers2

29

UPDATE: A more robust and faster implementation of address(x) (not using .Internal(inspect(x))) was added to data.table v1.8.9. From NEWS :

New function address() returns the address in RAM of its argument. Sometimes useful in determining whether a value has been copied or not by R, programatically.


There's probably a neater way but this seems to work.

address = function(x) substring(capture.output(.Internal(inspect(x)))[1],2,17)
x = 1
y = 1
z = x
identical(x,y)
# [1] TRUE
identical(x,z)
# [1] TRUE
address(x)==address(y)
# [1] FALSE
address(x)==address(z)
# [1] TRUE

You could modify it to work on 32bit by changing 17 to 9.

Matt Dowle
  • 58,872
  • 22
  • 166
  • 224
  • This is interesting. Do you know where I could read a bit more about when R actually creates new objects and when it just points to existing objects in memory? – Roland Jun 06 '12 at 11:47
  • 1
    @Roland Hm. I thought it would be easy to search and find some links, but it seems not. All I've found is [section 1.1.2 of R Internals](http://cran.r-project.org/doc/manuals/R-ints.html#Rest-of-header) which explains how the call-by-value illusion is implemented. I tend to experiment with `tracemem` and `.Internal(inspect(...))` to work out when copies are made. Doing that led to [this post to r-devel](http://r.789695.n4.nabble.com/Confused-about-NAMED-tp4103326.html) which might give some more clues. – Matt Dowle Jun 06 '12 at 12:58
  • Thank you. The thread on r-devel is quite interesting and I believe I learned something from it, though it is a bit above my current level of programming education. :) – Roland Jun 06 '12 at 13:12
  • @Roland Ok. Btw, a lot can be gleaned by looking at R's source. You can browse the latest committed SVN trunk [here](https://svn.r-project.org/R/trunk/). It's lean, mean and very well organised. So another way to see if something might copy is to look for a call to `duplicate`, for example. – Matt Dowle Jun 06 '12 at 13:42
  • 2
    Is it possible to write the inverse to `address`? – Matthew Lundberg Sep 01 '13 at 00:28
  • 1
    @MatthewLundberg Hm ... I suppose there could potentially be many symbols in many different environments all bound to the same address. _Possible_ though. Did you have a use in mind? Oh but you mean create a binding to the address and dereference it, like *p in C. That wouldn't be possible (I guess) because garbage collection might have cleared that object in the meantime. – Matt Dowle Sep 01 '13 at 00:45
  • 3
    Indeed, garbage collection may reap the object between the time the address was taken and the inverse called. This might crash the program, or worse, return an unrelated object. Because of this, the inverse to `address` sounds like a really bad idea. – Matthew Lundberg Sep 01 '13 at 01:04
  • A slightly more flexible version: `address <- sub(" .*", "", capture.output(.Internal(inspect(x)))[1])`. – datawookie Sep 22 '21 at 03:31
3

You can use the pryr package.

For example, return the memory location of the mtcars object:

pryr::address(mtcars)

Then, for variables a and b, you can check:

address(a) == address(b)
Megatron
  • 15,909
  • 12
  • 89
  • 97