2

I'm using SWIG to generate wrapper code to access C code from within the R language. The wrapper code uses the R externalptr type to hold references to C pointers. In some situations, those pointers are NULL on the C side, which show up in R as a nil value when displayed. On the R side, calling is.null() and is.na() on the externalptr both return FALSE. For example:

> val = librdf_query_results_get_binding_value(results, 2)
> val
An object of class "_p_librdf_node_s"
Slot "ref":
<pointer: (nil)>
> class(val@ref)
[1] "externalptr"
> is.null(val@ref)
[1] FALSE
> is.na(val@ref)
[1] FALSE

As can be seen from the code output above, the ref slot contains an externalptr, which is "nil". How do I determine from within R that this pointer in C is NULL?

If you want to see the code in context, it is available in GitHub: https://github.com/ropensci/redland-bindings/blob/master/R/redland/inst/tests/test.redland_base.R#L40

metamattj
  • 148
  • 9
  • 4
    I think you may need a C/C++ helper function that evaluates the external pointer for you. – Dirk Eddelbuettel Oct 31 '14 at 02:30
  • I think @DirkEddelbuettel is right. You might want to consider `bigmemory::is.nil` as a guide. – Joshua Ulrich Oct 31 '14 at 02:58
  • Thanks @DirkEddelbuettel, I suspected as much. So do you think that overriding is.null() for the `externalptr` type would be reasonable, or would it be better to put it in my own package? – metamattj Oct 31 '14 at 04:49

2 Answers2

5

The C solution above is most elegant, but a compiler might not always be available. A solution that does not require compiled code could be something like:

identical(pointer, new("externalptr"))

However this would not work if the object has custom attributes. If this is the case, you could do:

isnull <- function(pointer){
  a <- attributes(pointer)
  attributes(pointer) <- NULL
  out <- identical(pointer, new("externalptr"))
  attributes(pointer) <- a
  return(out)
}

Again a bit more involved than the C solution, but will work in a simple script on any platform.

Jeroen Ooms
  • 31,998
  • 35
  • 134
  • 207
4

For completeness, here's the solution I used. It required a function on the C side, and one on the R side, as suggested by @DirkEddelbuettel. The C function is:

#include <Rinternals.h>

SEXP isnull(SEXP pointer) {
  return ScalarLogical(!R_ExternalPtrAddr(pointer));
}

And the wrapper function in R is:

is.null.externalptr <- function(pointer) {
  stopifnot(is(pointer, "externalptr"))
  .Call("isnull", pointer)
}

For an example of use from within R:

> p <- new("externalptr")
> p
<pointer: (nil)>
> is.null.externalptr(p)
[1] TRUE
Jeroen Ooms
  • 31,998
  • 35
  • 134
  • 207
metamattj
  • 148
  • 9